mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 20:33:53 +01:00
Deleted unused classes related to modification (#3084)
Removed ModificationsSyncAdapter
This commit is contained in:
parent
75f3098c35
commit
386d08794e
14 changed files with 4 additions and 872 deletions
|
|
@ -162,17 +162,6 @@
|
|||
android:name="android.content.SyncAdapter"
|
||||
android:resource="@xml/contributions_sync_adapter" />
|
||||
</service>
|
||||
<service
|
||||
android:name=".modifications.ModificationsSyncService"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.content.SyncAdapter" />
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="android.content.SyncAdapter"
|
||||
android:resource="@xml/modifications_sync_adapter" />
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name="org.acra.sender.SenderService"
|
||||
|
|
@ -194,12 +183,7 @@
|
|||
android:exported="false"
|
||||
android:label="@string/provider_contributions"
|
||||
android:syncable="true" />
|
||||
<provider
|
||||
android:name=".modifications.ModificationsContentProvider"
|
||||
android:authorities="${applicationId}.modifications.contentprovider"
|
||||
android:exported="false"
|
||||
android:label="@string/provider_modifications"
|
||||
android:syncable="true" />
|
||||
|
||||
<provider
|
||||
android:name=".category.CategoryContentProvider"
|
||||
android:authorities="${applicationId}.categories.contentprovider"
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ import android.os.Build;
|
|||
import android.os.Process;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
import com.facebook.imagepipeline.core.ImagePipelineConfig;
|
||||
import com.squareup.leakcanary.LeakCanary;
|
||||
|
|
@ -28,7 +30,6 @@ import java.io.File;
|
|||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import fr.free.nrw.commons.auth.SessionManager;
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao;
|
||||
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao;
|
||||
|
|
@ -41,7 +42,6 @@ import fr.free.nrw.commons.di.ApplicationlessInjection;
|
|||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||
import fr.free.nrw.commons.logging.FileLoggingTree;
|
||||
import fr.free.nrw.commons.logging.LogUtils;
|
||||
import fr.free.nrw.commons.modifications.ModifierSequenceDao;
|
||||
import fr.free.nrw.commons.upload.FileUtils;
|
||||
import fr.free.nrw.commons.utils.ConfigUtils;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
|
|
@ -265,7 +265,6 @@ public class CommonsApplication extends Application {
|
|||
dbOpenHelper.getReadableDatabase().close();
|
||||
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
|
||||
|
||||
ModifierSequenceDao.Table.onDelete(db);
|
||||
CategoryDao.Table.onDelete(db);
|
||||
ContributionDao.Table.onDelete(db);
|
||||
BookmarkPicturesDao.Table.onDelete(db);
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao;
|
|||
import fr.free.nrw.commons.category.CategoryDao;
|
||||
import fr.free.nrw.commons.contributions.ContributionDao;
|
||||
import fr.free.nrw.commons.explore.recentsearches.RecentSearchesDao;
|
||||
import fr.free.nrw.commons.modifications.ModifierSequenceDao;
|
||||
|
||||
public class DBOpenHelper extends SQLiteOpenHelper {
|
||||
|
||||
|
|
@ -27,7 +26,6 @@ public class DBOpenHelper extends SQLiteOpenHelper {
|
|||
@Override
|
||||
public void onCreate(SQLiteDatabase sqLiteDatabase) {
|
||||
ContributionDao.Table.onCreate(sqLiteDatabase);
|
||||
ModifierSequenceDao.Table.onCreate(sqLiteDatabase);
|
||||
CategoryDao.Table.onCreate(sqLiteDatabase);
|
||||
BookmarkPicturesDao.Table.onCreate(sqLiteDatabase);
|
||||
BookmarkLocationsDao.Table.onCreate(sqLiteDatabase);
|
||||
|
|
@ -37,7 +35,6 @@ public class DBOpenHelper extends SQLiteOpenHelper {
|
|||
@Override
|
||||
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int from, int to) {
|
||||
ContributionDao.Table.onUpdate(sqLiteDatabase, from, to);
|
||||
ModifierSequenceDao.Table.onUpdate(sqLiteDatabase, from, to);
|
||||
CategoryDao.Table.onUpdate(sqLiteDatabase, from, to);
|
||||
BookmarkPicturesDao.Table.onUpdate(sqLiteDatabase, from, to);
|
||||
BookmarkLocationsDao.Table.onUpdate(sqLiteDatabase, from, to);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package fr.free.nrw.commons.di;
|
||||
|
||||
import fr.free.nrw.commons.contributions.ContributionsModule;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import dagger.Component;
|
||||
|
|
@ -10,8 +9,8 @@ import dagger.android.support.AndroidSupportInjectionModule;
|
|||
import fr.free.nrw.commons.CommonsApplication;
|
||||
import fr.free.nrw.commons.auth.LoginActivity;
|
||||
import fr.free.nrw.commons.contributions.ContributionViewHolder;
|
||||
import fr.free.nrw.commons.contributions.ContributionsModule;
|
||||
import fr.free.nrw.commons.contributions.ContributionsSyncAdapter;
|
||||
import fr.free.nrw.commons.modifications.ModificationsSyncAdapter;
|
||||
import fr.free.nrw.commons.nearby.PlaceRenderer;
|
||||
import fr.free.nrw.commons.review.ReviewController;
|
||||
import fr.free.nrw.commons.settings.SettingsFragment;
|
||||
|
|
@ -36,8 +35,6 @@ public interface CommonsApplicationComponent extends AndroidInjector<Application
|
|||
|
||||
void inject(ContributionsSyncAdapter syncAdapter);
|
||||
|
||||
void inject(ModificationsSyncAdapter syncAdapter);
|
||||
|
||||
void inject(LoginActivity activity);
|
||||
|
||||
void inject(SettingsFragment fragment);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesContentProvider;
|
|||
import fr.free.nrw.commons.category.CategoryContentProvider;
|
||||
import fr.free.nrw.commons.contributions.ContributionsContentProvider;
|
||||
import fr.free.nrw.commons.explore.recentsearches.RecentSearchesContentProvider;
|
||||
import fr.free.nrw.commons.modifications.ModificationsContentProvider;
|
||||
|
||||
@Module
|
||||
@SuppressWarnings({"WeakerAccess", "unused"})
|
||||
|
|
@ -16,9 +15,6 @@ public abstract class ContentProviderBuilderModule {
|
|||
@ContributesAndroidInjector
|
||||
abstract ContributionsContentProvider bindContributionsContentProvider();
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract ModificationsContentProvider bindModificationsContentProvider();
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract CategoryContentProvider bindCategoryContentProvider();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,48 +0,0 @@
|
|||
package fr.free.nrw.commons.modifications;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
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);
|
||||
|
||||
StringBuilder categoriesString = new StringBuilder();
|
||||
for (int i = 0; i < categories.length(); i++) {
|
||||
String category = categories.optString(i);
|
||||
categoriesString.append("\n[[Category:").append(category).append("]]");
|
||||
}
|
||||
return pageContents + categoriesString.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEditSummary() {
|
||||
return "Added " + params.optJSONArray(PARAM_CATEGORIES).length() + " categories.";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,161 +0,0 @@
|
|||
package fr.free.nrw.commons.modifications;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.UriMatcher;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteQueryBuilder;
|
||||
import android.net.Uri;
|
||||
import androidx.annotation.NonNull;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import fr.free.nrw.commons.BuildConfig;
|
||||
import fr.free.nrw.commons.data.DBOpenHelper;
|
||||
import fr.free.nrw.commons.di.CommonsDaggerContentProvider;
|
||||
import timber.log.Timber;
|
||||
|
||||
import static fr.free.nrw.commons.modifications.ModifierSequenceDao.Table.TABLE_NAME;
|
||||
|
||||
public class ModificationsContentProvider extends CommonsDaggerContentProvider {
|
||||
|
||||
private static final int MODIFICATIONS = 1;
|
||||
private static final int MODIFICATIONS_ID = 2;
|
||||
|
||||
public static final String BASE_PATH = "modifications";
|
||||
|
||||
public static final Uri BASE_URI = Uri.parse("content://" + BuildConfig.MODIFICATION_AUTHORITY + "/" + BASE_PATH);
|
||||
|
||||
private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
|
||||
static {
|
||||
uriMatcher.addURI(BuildConfig.MODIFICATION_AUTHORITY, BASE_PATH, MODIFICATIONS);
|
||||
uriMatcher.addURI(BuildConfig.MODIFICATION_AUTHORITY, BASE_PATH + "/#", MODIFICATIONS_ID);
|
||||
}
|
||||
|
||||
public static Uri uriForId(int id) {
|
||||
return Uri.parse(BASE_URI.toString() + "/" + id);
|
||||
}
|
||||
|
||||
@Inject DBOpenHelper dbOpenHelper;
|
||||
|
||||
@Override
|
||||
public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
|
||||
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
|
||||
queryBuilder.setTables(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(@NonNull Uri uri) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uri insert(@NonNull Uri uri, ContentValues contentValues) {
|
||||
int uriType = uriMatcher.match(uri);
|
||||
SQLiteDatabase sqlDB = dbOpenHelper.getWritableDatabase();
|
||||
long id;
|
||||
switch (uriType) {
|
||||
case MODIFICATIONS:
|
||||
id = sqlDB.insert(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(@NonNull 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(TABLE_NAME,
|
||||
"_id = ?",
|
||||
new String[] { id }
|
||||
);
|
||||
return 1;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown URI: " + uri);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bulkInsert(@NonNull Uri uri, @NonNull ContentValues[] values) {
|
||||
Timber.d("Hello, bulk insert! (ModificationsContentProvider)");
|
||||
int uriType = uriMatcher.match(uri);
|
||||
SQLiteDatabase sqlDB = dbOpenHelper.getWritableDatabase();
|
||||
sqlDB.beginTransaction();
|
||||
switch (uriType) {
|
||||
case MODIFICATIONS:
|
||||
for (ContentValues value: values) {
|
||||
Timber.d("Inserting! %s", value);
|
||||
sqlDB.insert(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(@NonNull 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;
|
||||
switch (uriType) {
|
||||
case MODIFICATIONS:
|
||||
rowsUpdated = sqlDB.update(TABLE_NAME,
|
||||
contentValues,
|
||||
selection,
|
||||
selectionArgs);
|
||||
break;
|
||||
case MODIFICATIONS_ID:
|
||||
int id = Integer.valueOf(uri.getLastPathSegment());
|
||||
|
||||
if (TextUtils.isEmpty(selection)) {
|
||||
rowsUpdated = sqlDB.update(TABLE_NAME,
|
||||
contentValues,
|
||||
ModifierSequenceDao.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;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,126 +0,0 @@
|
|||
package fr.free.nrw.commons.modifications;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.content.AbstractThreadedSyncAdapter;
|
||||
import android.content.ContentProviderClient;
|
||||
import android.content.Context;
|
||||
import android.content.SyncResult;
|
||||
import android.database.Cursor;
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import fr.free.nrw.commons.BuildConfig;
|
||||
import fr.free.nrw.commons.actions.PageEditClient;
|
||||
import fr.free.nrw.commons.auth.SessionManager;
|
||||
import fr.free.nrw.commons.contributions.Contribution;
|
||||
import fr.free.nrw.commons.contributions.ContributionDao;
|
||||
import fr.free.nrw.commons.di.ApplicationlessInjection;
|
||||
import fr.free.nrw.commons.mwapi.MediaWikiApi;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.functions.Consumer;
|
||||
import timber.log.Timber;
|
||||
|
||||
public class ModificationsSyncAdapter extends AbstractThreadedSyncAdapter {
|
||||
|
||||
@Inject MediaWikiApi mwApi;
|
||||
@Inject ContributionDao contributionDao;
|
||||
@Inject ModifierSequenceDao modifierSequenceDao;
|
||||
@Inject
|
||||
SessionManager sessionManager;
|
||||
@Inject
|
||||
@Named("commons-page-edit")
|
||||
PageEditClient commonsPageEditClient;
|
||||
|
||||
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!
|
||||
ApplicationlessInjection
|
||||
.getInstance(getContext()
|
||||
.getApplicationContext())
|
||||
.getCommonsApplicationComponent()
|
||||
.inject(this);
|
||||
|
||||
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) {
|
||||
Timber.d("No modifications to perform");
|
||||
return;
|
||||
}
|
||||
|
||||
allModifications.moveToFirst();
|
||||
|
||||
Timber.d("Found %d modifications to execute", allModifications.getCount());
|
||||
|
||||
ContentProviderClient contributionsClient = null;
|
||||
try {
|
||||
contributionsClient = getContext().getContentResolver().acquireContentProviderClient(BuildConfig.CONTRIBUTION_AUTHORITY);
|
||||
|
||||
while (!allModifications.isAfterLast()) {
|
||||
ModifierSequence sequence = modifierSequenceDao.fromCursor(allModifications);
|
||||
Contribution contrib;
|
||||
Cursor contributionCursor;
|
||||
|
||||
if (contributionsClient == null) {
|
||||
Timber.e("ContributionsClient is null. This should not happen!");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
contributionCursor = contributionsClient.query(sequence.getMediaUri(), null, null, null, null);
|
||||
} catch (RemoteException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
if (contributionCursor != null) {
|
||||
contributionCursor.moveToFirst();
|
||||
}
|
||||
|
||||
contrib = contributionDao.fromCursor(contributionCursor);
|
||||
|
||||
if (contrib != null && contrib.getState() == Contribution.STATE_COMPLETED) {
|
||||
String pageContent;
|
||||
try {
|
||||
pageContent = mwApi.revisionsByFilename(contrib.getFilename());
|
||||
} catch (IOException e) {
|
||||
Timber.d("Network messed up on modifications sync!");
|
||||
continue;
|
||||
}
|
||||
|
||||
Timber.d("Page content is %s", pageContent);
|
||||
String processedPageContent = sequence.executeModifications(contrib.getFilename(), pageContent);
|
||||
|
||||
Disposable disposable = commonsPageEditClient
|
||||
.edit(contrib.getFilename(), processedPageContent, sequence.getEditSummary())
|
||||
.subscribe(editResult -> {
|
||||
if (!editResult) {
|
||||
Timber.d("Non success result!");
|
||||
} else {
|
||||
modifierSequenceDao.delete(sequence);
|
||||
}
|
||||
});
|
||||
}
|
||||
allModifications.moveToNext();
|
||||
}
|
||||
} finally {
|
||||
if (contributionsClient != null) {
|
||||
contributionsClient.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
package fr.free.nrw.commons.modifications;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
|
||||
public class ModificationsSyncService extends Service {
|
||||
|
||||
private static final Object sSyncAdapterLock = new Object();
|
||||
|
||||
private static ModificationsSyncAdapter sSyncAdapter = null;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
synchronized (sSyncAdapterLock) {
|
||||
if (sSyncAdapter == null) {
|
||||
sSyncAdapter = new ModificationsSyncAdapter(this, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return sSyncAdapter.getSyncAdapterBinder();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
package fr.free.nrw.commons.modifications;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ModifierSequence {
|
||||
private Uri mediaUri;
|
||||
private ArrayList<PageModifier> modifiers;
|
||||
private Uri contentUri;
|
||||
|
||||
public ModifierSequence(Uri mediaUri) {
|
||||
this.mediaUri = mediaUri;
|
||||
modifiers = new ArrayList<>();
|
||||
}
|
||||
|
||||
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)));
|
||||
}
|
||||
}
|
||||
|
||||
Uri getMediaUri() {
|
||||
return mediaUri;
|
||||
}
|
||||
|
||||
public void queueModifier(PageModifier modifier) {
|
||||
modifiers.add(modifier);
|
||||
}
|
||||
|
||||
String executeModifications(String pageName, String pageContents) {
|
||||
for (PageModifier modifier: modifiers) {
|
||||
pageContents = modifier.doModification(pageName, pageContents);
|
||||
}
|
||||
return pageContents;
|
||||
}
|
||||
|
||||
String getEditSummary() {
|
||||
StringBuilder editSummary = new StringBuilder();
|
||||
for (PageModifier modifier: modifiers) {
|
||||
editSummary.append(modifier.getEditSummary()).append(" ");
|
||||
}
|
||||
editSummary.append("Using [[COM:MOA|Commons Mobile App]]");
|
||||
return editSummary.toString();
|
||||
}
|
||||
|
||||
ArrayList<PageModifier> getModifiers() {
|
||||
return modifiers;
|
||||
}
|
||||
|
||||
Uri getContentUri() {
|
||||
return contentUri;
|
||||
}
|
||||
|
||||
void setContentUri(Uri contentUri) {
|
||||
this.contentUri = contentUri;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
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;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Provider;
|
||||
|
||||
public class ModifierSequenceDao {
|
||||
|
||||
private final Provider<ContentProviderClient> clientProvider;
|
||||
|
||||
@Inject
|
||||
public ModifierSequenceDao(@Named("modification") Provider<ContentProviderClient> clientProvider) {
|
||||
this.clientProvider = clientProvider;
|
||||
}
|
||||
|
||||
public void save(ModifierSequence sequence) {
|
||||
ContentProviderClient db = clientProvider.get();
|
||||
try {
|
||||
if (sequence.getContentUri() == null) {
|
||||
sequence.setContentUri(db.insert(ModificationsContentProvider.BASE_URI, toContentValues(sequence)));
|
||||
} else {
|
||||
db.update(sequence.getContentUri(), toContentValues(sequence), null, null);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
db.release();
|
||||
}
|
||||
}
|
||||
|
||||
public void delete(ModifierSequence sequence) {
|
||||
ContentProviderClient db = clientProvider.get();
|
||||
try {
|
||||
db.delete(sequence.getContentUri(), null, null);
|
||||
} catch (RemoteException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
db.release();
|
||||
}
|
||||
}
|
||||
|
||||
ModifierSequence fromCursor(Cursor cursor) {
|
||||
// Hardcoding column positions!
|
||||
ModifierSequence ms;
|
||||
try {
|
||||
ms = new ModifierSequence(Uri.parse(cursor.getString(cursor.getColumnIndex(Table.COLUMN_MEDIA_URI))),
|
||||
new JSONObject(cursor.getString(cursor.getColumnIndex(Table.COLUMN_DATA))));
|
||||
} catch (JSONException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
ms.setContentUri( ModificationsContentProvider.uriForId(cursor.getInt(cursor.getColumnIndex(Table.COLUMN_ID))));
|
||||
|
||||
return ms;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
package fr.free.nrw.commons.modifications;
|
||||
|
||||
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"));
|
||||
} else if (name.equals(TemplateRemoveModifier.MODIFIER_NAME)) {
|
||||
return new TemplateRemoveModifier(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 abstract String getEditSummary();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
package fr.free.nrw.commons.modifications;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class TemplateRemoveModifier extends PageModifier {
|
||||
|
||||
public static final String MODIFIER_NAME = "TemplateRemoverModifier";
|
||||
|
||||
public static final String PARAM_TEMPLATE_NAME = "template";
|
||||
|
||||
public static final Pattern PATTERN_TEMPLATE_OPEN = Pattern.compile("\\{\\{");
|
||||
public static final Pattern PATTERN_TEMPLATE_CLOSE = Pattern.compile("\\}\\}");
|
||||
|
||||
public TemplateRemoveModifier(String templateName) {
|
||||
super(MODIFIER_NAME);
|
||||
try {
|
||||
params.putOpt(PARAM_TEMPLATE_NAME, templateName);
|
||||
} catch (JSONException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public TemplateRemoveModifier(JSONObject data) {
|
||||
super(MODIFIER_NAME);
|
||||
this.params = data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String doModification(String pageName, String pageContents) {
|
||||
String templateRawName = params.optString(PARAM_TEMPLATE_NAME);
|
||||
// Wikitext title normalizing rules. Spaces and _ equivalent
|
||||
// They also 'condense' - any number of them reduce to just one (just like HTML)
|
||||
String templateNormalized = templateRawName.trim().replaceAll("(\\s|_)+", "(\\s|_)+");
|
||||
|
||||
// Not supporting {{ inside <nowiki> and HTML comments yet
|
||||
// (Thanks to marktraceur for reminding me of the HTML comments exception)
|
||||
Pattern templateStartPattern = Pattern.compile("\\{\\{" + templateNormalized, Pattern.CASE_INSENSITIVE);
|
||||
Matcher matcher = templateStartPattern.matcher(pageContents);
|
||||
|
||||
while (matcher.find()) {
|
||||
int braceCount = 1;
|
||||
int startIndex = matcher.start();
|
||||
int curIndex = matcher.end();
|
||||
Matcher openMatch = PATTERN_TEMPLATE_OPEN.matcher(pageContents);
|
||||
Matcher closeMatch = PATTERN_TEMPLATE_CLOSE.matcher(pageContents);
|
||||
|
||||
while (curIndex < pageContents.length()) {
|
||||
boolean openFound = openMatch.find(curIndex);
|
||||
boolean closeFound = closeMatch.find(curIndex);
|
||||
|
||||
if (openFound && (!closeFound || openMatch.start() < closeMatch.start())) {
|
||||
braceCount++;
|
||||
curIndex = openMatch.end();
|
||||
} else if (closeFound) {
|
||||
braceCount--;
|
||||
curIndex = closeMatch.end();
|
||||
} else if (braceCount > 0) {
|
||||
// The template never closes, so...remove nothing
|
||||
curIndex = startIndex;
|
||||
break;
|
||||
}
|
||||
|
||||
if (braceCount == 0) {
|
||||
// The braces have all been closed!
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Strip trailing whitespace
|
||||
while (curIndex < pageContents.length()) {
|
||||
if (pageContents.charAt(curIndex) == ' ' || pageContents.charAt(curIndex) == '\n') {
|
||||
curIndex++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// I am so going to hell for this, sigh
|
||||
pageContents = pageContents.substring(0, startIndex) + pageContents.substring(curIndex);
|
||||
matcher = templateStartPattern.matcher(pageContents);
|
||||
}
|
||||
|
||||
return pageContents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEditSummary() {
|
||||
return "Removed template " + params.optString(PARAM_TEMPLATE_NAME) + ".";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,156 +0,0 @@
|
|||
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 com.nhaarman.mockito_kotlin.*
|
||||
import fr.free.nrw.commons.BuildConfig
|
||||
import fr.free.nrw.commons.TestCommonsApplication
|
||||
import fr.free.nrw.commons.modifications.ModificationsContentProvider.BASE_URI
|
||||
import fr.free.nrw.commons.modifications.ModifierSequenceDao.Table.*
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(sdk = [21], application = TestCommonsApplication::class)
|
||||
class ModifierSequenceDaoTest {
|
||||
|
||||
private val mediaUrl = "http://example.com/"
|
||||
private val columns = arrayOf(COLUMN_ID, COLUMN_MEDIA_URI, COLUMN_DATA)
|
||||
private val client: ContentProviderClient = mock()
|
||||
private val database: SQLiteDatabase = mock()
|
||||
private val contentValuesCaptor = argumentCaptor<ContentValues>()
|
||||
|
||||
private lateinit var testObject: ModifierSequenceDao
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
testObject = ModifierSequenceDao { client }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun createFromCursorWithEmptyModifiers() {
|
||||
testObject.fromCursor(createCursor("")).let {
|
||||
assertEquals(mediaUrl, it.mediaUri.toString())
|
||||
assertEquals(BASE_URI.buildUpon().appendPath("1").toString(), it.contentUri.toString())
|
||||
assertTrue(it.modifiers.isEmpty())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun createFromCursorWtihCategoryModifier() {
|
||||
val cursor = createCursor("{\"name\": \"CategoriesModifier\", \"data\": {}}")
|
||||
|
||||
val seq = testObject.fromCursor(cursor)
|
||||
|
||||
assertEquals(1, seq.modifiers.size)
|
||||
assertTrue(seq.modifiers[0] is CategoryModifier)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun createFromCursorWithRemoveModifier() {
|
||||
val cursor = createCursor("{\"name\": \"TemplateRemoverModifier\", \"data\": {}}")
|
||||
|
||||
val seq = testObject.fromCursor(cursor)
|
||||
|
||||
assertEquals(1, seq.modifiers.size)
|
||||
assertTrue(seq.modifiers[0] is TemplateRemoveModifier)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun deleteSequence() {
|
||||
whenever(client.delete(isA(), isNull(), isNull())).thenReturn(1)
|
||||
val seq = testObject.fromCursor(createCursor(""))
|
||||
|
||||
testObject.delete(seq)
|
||||
|
||||
verify(client).delete(eq(seq.contentUri), isNull(), isNull())
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException::class)
|
||||
fun deleteTranslatesRemoteExceptions() {
|
||||
whenever(client.delete(isA(), isNull(), isNull())).thenThrow(RemoteException(""))
|
||||
val seq = testObject.fromCursor(createCursor(""))
|
||||
|
||||
testObject.delete(seq)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun saveExistingSequence() {
|
||||
val modifierJson = "{\"name\":\"CategoriesModifier\",\"data\":{}}"
|
||||
val expectedData = "{\"modifiers\":[$modifierJson]}"
|
||||
val cursor = createCursor(modifierJson)
|
||||
val seq = testObject.fromCursor(cursor)
|
||||
|
||||
testObject.save(seq)
|
||||
|
||||
verify(client).update(eq(seq.contentUri), contentValuesCaptor.capture(), isNull(), isNull())
|
||||
contentValuesCaptor.firstValue.let {
|
||||
assertEquals(2, it.size())
|
||||
assertEquals(mediaUrl, it.get(COLUMN_MEDIA_URI))
|
||||
assertEquals(expectedData, it.get(COLUMN_DATA))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun saveNewSequence() {
|
||||
val expectedContentUri = BASE_URI.buildUpon().appendPath("1").build()
|
||||
whenever(client.insert(isA(), isA())).thenReturn(expectedContentUri)
|
||||
val seq = ModifierSequence(Uri.parse(mediaUrl))
|
||||
|
||||
testObject.save(seq)
|
||||
|
||||
assertEquals(expectedContentUri.toString(), seq.contentUri.toString())
|
||||
verify(client).insert(eq(ModificationsContentProvider.BASE_URI), contentValuesCaptor.capture())
|
||||
contentValuesCaptor.firstValue.let {
|
||||
assertEquals(2, it.size())
|
||||
assertEquals(mediaUrl, it.get(COLUMN_MEDIA_URI))
|
||||
assertEquals("{\"modifiers\":[]}", it.get(COLUMN_DATA))
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException::class)
|
||||
fun saveTranslatesRemoteExceptions() {
|
||||
whenever(client.insert(isA(), isA())).thenThrow(RemoteException(""))
|
||||
testObject.save(ModifierSequence(Uri.parse(mediaUrl)))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun createTable() {
|
||||
onCreate(database)
|
||||
verify(database).execSQL(CREATE_TABLE_STATEMENT)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun updateTable() {
|
||||
onUpdate(database, 1, 2)
|
||||
|
||||
inOrder(database) {
|
||||
verify<SQLiteDatabase>(database).execSQL(DROP_TABLE_STATEMENT)
|
||||
verify<SQLiteDatabase>(database).execSQL(CREATE_TABLE_STATEMENT)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun deleteTable() {
|
||||
onDelete(database)
|
||||
|
||||
inOrder(database) {
|
||||
verify<SQLiteDatabase>(database).execSQL(DROP_TABLE_STATEMENT)
|
||||
verify<SQLiteDatabase>(database).execSQL(CREATE_TABLE_STATEMENT)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createCursor(modifierJson: String) = MatrixCursor(columns, 1).apply {
|
||||
addRow(listOf("1", mediaUrl, "{\"modifiers\": [$modifierJson]}"))
|
||||
moveToFirst()
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue