mirror of https://github.com/tasks/tasks
Remove new sync migrator
parent
09eef62645
commit
0e4e7ee50e
@ -1,168 +0,0 @@
|
||||
package com.todoroo.astrid.sync;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.todoroo.andlib.data.Property;
|
||||
import com.todoroo.andlib.data.Property.LongProperty;
|
||||
import com.todoroo.andlib.data.Table;
|
||||
import com.todoroo.andlib.data.TodorooCursor;
|
||||
import com.todoroo.andlib.service.Autowired;
|
||||
import com.todoroo.andlib.sql.Query;
|
||||
import com.todoroo.andlib.utility.Preferences;
|
||||
import com.todoroo.astrid.actfm.sync.AstridNewSyncMigrator;
|
||||
import com.todoroo.astrid.dao.MetadataDao;
|
||||
import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
|
||||
import com.todoroo.astrid.dao.RemoteModelDao;
|
||||
import com.todoroo.astrid.data.Metadata;
|
||||
import com.todoroo.astrid.data.RemoteModel;
|
||||
import com.todoroo.astrid.data.SyncFlags;
|
||||
import com.todoroo.astrid.data.TagData;
|
||||
import com.todoroo.astrid.data.Task;
|
||||
import com.todoroo.astrid.tags.TaskToTagMetadata;
|
||||
|
||||
public class AstridNewSyncMigrationTest extends NewSyncTestCase {
|
||||
|
||||
private static final LongProperty TASK_REMOTE_ID_FIELD = new LongProperty(Task.TABLE, RemoteModel.UUID_PROPERTY_NAME);
|
||||
private static final LongProperty TAG_REMOTE_ID_FIELD = new LongProperty(TagData.TABLE, RemoteModel.UUID_PROPERTY_NAME);
|
||||
|
||||
@Autowired
|
||||
private MetadataDao metadataDao;
|
||||
|
||||
public void testAstridSyncMigration() {
|
||||
setupOldDatabase();
|
||||
Preferences.setBoolean(AstridNewSyncMigrator.PREF_SYNC_MIGRATION, false);
|
||||
new AstridNewSyncMigrator().performMigration();
|
||||
assertAllModelsHaveUUID();
|
||||
assertAllTagsHaveTagData();
|
||||
assertAllMetadataHasAllFields();
|
||||
}
|
||||
|
||||
private void setupOldDatabase() {
|
||||
// Init 5 unsynced tasks and tags
|
||||
for (int i = 1; i <= 5; i++) {
|
||||
Task task = createTask("Task " + i, true);
|
||||
task.setValue(TASK_REMOTE_ID_FIELD, null);
|
||||
taskDao.save(task);
|
||||
|
||||
TagData tag = createTagData("Tag " + i, true);
|
||||
tag.setValue(TAG_REMOTE_ID_FIELD, null);
|
||||
tagDataDao.saveExisting(tag);
|
||||
}
|
||||
|
||||
Metadata m = new Metadata();
|
||||
m.setValue(Metadata.KEY, TaskToTagMetadata.KEY);
|
||||
m.setValue(Metadata.TASK, 1L);
|
||||
m.setValue(TaskToTagMetadata.TAG_NAME, "Tag 1");
|
||||
m.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true);
|
||||
metadataDao.createNew(m);
|
||||
m.clear();
|
||||
|
||||
m.setValue(Metadata.KEY, TaskToTagMetadata.KEY);
|
||||
m.setValue(Metadata.TASK, 2L);
|
||||
m.setValue(TaskToTagMetadata.TAG_NAME, "New tag");
|
||||
m.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true);
|
||||
metadataDao.createNew(m);
|
||||
m.clear();
|
||||
|
||||
m.setValue(Metadata.KEY, TaskToTagMetadata.KEY);
|
||||
m.setValue(Metadata.TASK, 3L);
|
||||
m.setValue(TaskToTagMetadata.TAG_NAME, "Tag 3");
|
||||
m.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true);
|
||||
metadataDao.createNew(m);
|
||||
m.clear();
|
||||
|
||||
m.setValue(Metadata.KEY, TaskToTagMetadata.KEY);
|
||||
m.setValue(Metadata.TASK, 3L);
|
||||
m.setValue(TaskToTagMetadata.TAG_NAME, "Tag 4");
|
||||
m.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true);
|
||||
metadataDao.createNew(m);
|
||||
m.clear();
|
||||
|
||||
m.setValue(Metadata.KEY, TaskToTagMetadata.KEY);
|
||||
m.setValue(Metadata.TASK, 5L);
|
||||
m.setValue(TaskToTagMetadata.TAG_NAME, "Tag 1");
|
||||
m.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true);
|
||||
metadataDao.createNew(m);
|
||||
m.clear();
|
||||
|
||||
m.setValue(Metadata.KEY, TaskToTagMetadata.KEY);
|
||||
m.setValue(Metadata.TASK, 5L);
|
||||
m.setValue(TaskToTagMetadata.TAG_NAME, "Tag 5");
|
||||
m.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true);
|
||||
metadataDao.createNew(m);
|
||||
|
||||
m.setValue(Metadata.KEY, TaskToTagMetadata.KEY);
|
||||
m.setValue(Metadata.TASK, 5L);
|
||||
m.setValue(TaskToTagMetadata.TAG_NAME, "New tag 2");
|
||||
m.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true);
|
||||
metadataDao.createNew(m);
|
||||
|
||||
// State (task: tags)
|
||||
// Task 1: Tag 1
|
||||
// Task 2: New tag
|
||||
// Task 3: Tag 3, Tag 4
|
||||
// Task 4: (nothing)
|
||||
// Task 5: Tag 5, New tag 2
|
||||
}
|
||||
|
||||
private void assertAllModelsHaveUUID() {
|
||||
assertUUIDs(Task.TABLE, new Task(), taskDao, Task.ID, Task.UUID);
|
||||
assertUUIDs(TagData.TABLE, new TagData(), tagDataDao, TagData.ID, TagData.UUID);
|
||||
}
|
||||
|
||||
private <TYPE extends RemoteModel> void assertUUIDs(Table table, TYPE instance, RemoteModelDao<TYPE> dao, Property<?>... properties) {
|
||||
TodorooCursor<TYPE> cursor = dao.query(Query.select(properties).from(table));
|
||||
try {
|
||||
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
|
||||
instance.clear();
|
||||
instance.readPropertiesFromCursor(cursor);
|
||||
String uuid = instance.getValue(RemoteModel.UUID_PROPERTY);
|
||||
if (uuid == null || RemoteModel.NO_UUID.equals(uuid)) {
|
||||
fail(instance.getClass().getName() + " " + instance.getId() + " didn't have a uuid");
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void assertAllTagsHaveTagData() {
|
||||
ArrayList<String> names = new ArrayList<String>();
|
||||
for (int i = 1; i <= 5; i++) {
|
||||
String name = "Tag " + i;
|
||||
names.add(name);
|
||||
}
|
||||
names.add("New tag");
|
||||
names.add("New tag 2");
|
||||
|
||||
String[] namesArray = names.toArray(new String[names.size()]);
|
||||
TodorooCursor<TagData> tagData = tagDataDao.query(Query.select(TagData.NAME).where(TagData.NAME.in(namesArray)));
|
||||
try {
|
||||
assertEquals(namesArray.length, tagData.getCount());
|
||||
} finally {
|
||||
tagData.close();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void assertAllMetadataHasAllFields() {
|
||||
TodorooCursor<Metadata> tagMetadata = metadataDao.query(Query.select(Metadata.PROPERTIES)
|
||||
.where(MetadataCriteria.withKey(TaskToTagMetadata.KEY)));
|
||||
try {
|
||||
assertEquals(tagMetadata.getCount(), 7);
|
||||
Metadata m = new Metadata();
|
||||
for (tagMetadata.moveToFirst(); !tagMetadata.isAfterLast(); tagMetadata.moveToNext()) {
|
||||
m.readFromCursor(tagMetadata);
|
||||
assertTrue(!TextUtils.isEmpty(m.getValue(TaskToTagMetadata.TAG_NAME)));
|
||||
assertTrue(!RemoteModel.NO_UUID.equals(m.getValue(TaskToTagMetadata.TASK_UUID)));
|
||||
assertTrue(!RemoteModel.NO_UUID.equals(m.getValue(TaskToTagMetadata.TAG_UUID)));
|
||||
}
|
||||
} finally {
|
||||
tagMetadata.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,640 +0,0 @@
|
||||
package com.todoroo.astrid.actfm.sync;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.todoroo.andlib.data.DatabaseDao;
|
||||
import com.todoroo.andlib.data.Property;
|
||||
import com.todoroo.andlib.data.TodorooCursor;
|
||||
import com.todoroo.andlib.service.Autowired;
|
||||
import com.todoroo.andlib.service.DependencyInjectionService;
|
||||
import com.todoroo.andlib.sql.Criterion;
|
||||
import com.todoroo.andlib.sql.Functions;
|
||||
import com.todoroo.andlib.sql.Order;
|
||||
import com.todoroo.andlib.sql.Query;
|
||||
import com.todoroo.andlib.utility.DateUtilities;
|
||||
import com.todoroo.andlib.utility.Preferences;
|
||||
import com.todoroo.astrid.actfm.sync.messages.NameMaps;
|
||||
import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
|
||||
import com.todoroo.astrid.dao.OutstandingEntryDao;
|
||||
import com.todoroo.astrid.dao.RemoteModelDao;
|
||||
import com.todoroo.astrid.dao.TagDataDao;
|
||||
import com.todoroo.astrid.dao.TagOutstandingDao;
|
||||
import com.todoroo.astrid.dao.TaskAttachmentDao;
|
||||
import com.todoroo.astrid.dao.TaskDao;
|
||||
import com.todoroo.astrid.dao.TaskListMetadataDao;
|
||||
import com.todoroo.astrid.dao.TaskOutstandingDao;
|
||||
import com.todoroo.astrid.dao.UpdateDao;
|
||||
import com.todoroo.astrid.dao.UserActivityDao;
|
||||
import com.todoroo.astrid.dao.UserDao;
|
||||
import com.todoroo.astrid.data.Metadata;
|
||||
import com.todoroo.astrid.data.OutstandingEntry;
|
||||
import com.todoroo.astrid.data.RemoteModel;
|
||||
import com.todoroo.astrid.data.SyncFlags;
|
||||
import com.todoroo.astrid.data.TagData;
|
||||
import com.todoroo.astrid.data.TagOutstanding;
|
||||
import com.todoroo.astrid.data.Task;
|
||||
import com.todoroo.astrid.data.TaskAttachment;
|
||||
import com.todoroo.astrid.data.TaskListMetadata;
|
||||
import com.todoroo.astrid.data.TaskOutstanding;
|
||||
import com.todoroo.astrid.data.Update;
|
||||
import com.todoroo.astrid.data.User;
|
||||
import com.todoroo.astrid.data.UserActivity;
|
||||
import com.todoroo.astrid.files.FileMetadata;
|
||||
import com.todoroo.astrid.helper.UUIDHelper;
|
||||
import com.todoroo.astrid.service.MetadataService;
|
||||
import com.todoroo.astrid.service.TagDataService;
|
||||
import com.todoroo.astrid.subtasks.SubtasksHelper;
|
||||
import com.todoroo.astrid.subtasks.SubtasksUpdater;
|
||||
import com.todoroo.astrid.tags.TaskToTagMetadata;
|
||||
|
||||
public class AstridNewSyncMigrator {
|
||||
|
||||
@Autowired private MetadataService metadataService;
|
||||
@Autowired private TagDataService tagDataService;
|
||||
@Autowired private TagDataDao tagDataDao;
|
||||
@Autowired private TaskDao taskDao;
|
||||
@Autowired private UpdateDao updateDao;
|
||||
@Autowired private UserActivityDao userActivityDao;
|
||||
@Autowired private UserDao userDao;
|
||||
@Autowired private TaskAttachmentDao taskAttachmentDao;
|
||||
@Autowired private TaskListMetadataDao taskListMetadataDao;
|
||||
|
||||
@Autowired private TaskOutstandingDao taskOutstandingDao;
|
||||
@Autowired private TagOutstandingDao tagOutstandingDao;
|
||||
|
||||
private static final String LOG_TAG = "sync-migrate";
|
||||
|
||||
public static final String PREF_SYNC_MIGRATION = "p_sync_migration";
|
||||
|
||||
public AstridNewSyncMigrator() {
|
||||
DependencyInjectionService.getInstance().inject(this);
|
||||
}
|
||||
|
||||
public void performMigration() {
|
||||
if (Preferences.getBoolean(PREF_SYNC_MIGRATION, false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// --------------
|
||||
// First ensure that a TagData object exists for each tag metadata
|
||||
// --------------
|
||||
Query noTagDataQuery = Query.select(Metadata.PROPERTIES).where(Criterion.and(
|
||||
MetadataCriteria.withKey(TaskToTagMetadata.KEY),
|
||||
Criterion.or(TaskToTagMetadata.TAG_UUID.isNull(), TaskToTagMetadata.TAG_UUID.eq(0)),
|
||||
Criterion.not(TaskToTagMetadata.TAG_NAME.in(Query.select(TagData.NAME).from(TagData.TABLE))))).groupBy(TaskToTagMetadata.TAG_NAME);
|
||||
|
||||
TodorooCursor<Metadata> noTagData = null;
|
||||
try {
|
||||
noTagData = metadataService.query(noTagDataQuery);
|
||||
Metadata tag = new Metadata();
|
||||
TagData newTagData = new TagData();
|
||||
for (noTagData.moveToFirst(); !noTagData.isAfterLast(); noTagData.moveToNext()) {
|
||||
try {
|
||||
newTagData.clear();
|
||||
tag.clear();
|
||||
tag.readFromCursor(noTagData);
|
||||
|
||||
if (ActFmInvoker.SYNC_DEBUG) {
|
||||
Log.w(LOG_TAG, "CREATING TAG DATA " + tag.getValue(TaskToTagMetadata.TAG_NAME));
|
||||
}
|
||||
|
||||
newTagData.setValue(TagData.NAME, tag.getValue(TaskToTagMetadata.TAG_NAME));
|
||||
tagDataService.save(newTagData);
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "Error creating tag data", e);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "Error creating tag data", e);
|
||||
} finally {
|
||||
if (noTagData != null) {
|
||||
noTagData.close();
|
||||
}
|
||||
}
|
||||
|
||||
// --------------
|
||||
// Delete all emergent tag data, we don't need it
|
||||
// --------------
|
||||
TodorooCursor<TagData> emergentTags = null;
|
||||
try {
|
||||
emergentTags = tagDataDao.query(Query.select(TagData.ID, TagData.NAME).where(Functions.bitwiseAnd(TagData.FLAGS, TagData.FLAG_EMERGENT).gt(0)));
|
||||
TagData td = new TagData();
|
||||
for (emergentTags.moveToFirst(); !emergentTags.isAfterLast(); emergentTags.moveToNext()) {
|
||||
try {
|
||||
td.clear();
|
||||
td.readFromCursor(emergentTags);
|
||||
String name = td.getValue(TagData.NAME);
|
||||
tagDataDao.delete(td.getId());
|
||||
if (!TextUtils.isEmpty(name)) {
|
||||
metadataService.deleteWhere(Criterion.and(MetadataCriteria.withKey(TaskToTagMetadata.KEY), TaskToTagMetadata.TAG_NAME.eq(name)));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "Error clearing emergent tags");
|
||||
}
|
||||
}
|
||||
} catch (Exception e){
|
||||
} finally {
|
||||
if (emergentTags != null) {
|
||||
emergentTags.close();
|
||||
}
|
||||
}
|
||||
|
||||
// --------------
|
||||
// Then ensure that every remote model has a remote id, by generating one using the uuid generator for all those without one
|
||||
// --------------
|
||||
final Set<Long> tasksThatNeedTagSync = new HashSet<Long>();
|
||||
try {
|
||||
Query tagsQuery = Query.select(TagData.ID, TagData.UUID, TagData.MODIFICATION_DATE)
|
||||
.where(Criterion.or(TagData.UUID.eq(RemoteModel.NO_UUID), TagData.UUID.isNull(), TagData.UUID.eq("")));
|
||||
assertUUIDsExist(tagsQuery, new TagData(), tagDataDao, tagOutstandingDao, new TagOutstanding(), NameMaps.syncableProperties(NameMaps.TABLE_ID_TAGS), new UUIDAssertionExtras<TagData>() {
|
||||
private static final String LAST_TAG_FETCH_TIME = "actfm_lastTag"; //$NON-NLS-1$
|
||||
private final long lastFetchTime = Preferences.getInt(LAST_TAG_FETCH_TIME, 0) * 1000L;
|
||||
|
||||
@Override
|
||||
public boolean shouldCreateOutstandingEntries(TagData instance) {
|
||||
boolean result = lastFetchTime == 0 || (instance.containsNonNullValue(TagData.MODIFICATION_DATE) && instance.getValue(TagData.MODIFICATION_DATE) > lastFetchTime);
|
||||
return result && RemoteModelDao.getOutstandingEntryFlag(RemoteModelDao.OUTSTANDING_ENTRY_FLAG_RECORD_OUTSTANDING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterSave(TagData instance, boolean createdOutstanding) {/**/}
|
||||
});
|
||||
|
||||
Query tasksQuery = Query.select(Task.ID, Task.UUID, Task.RECURRENCE, Task.FLAGS, Task.MODIFICATION_DATE, Task.LAST_SYNC)
|
||||
.where(Criterion.or(Task.UUID.eq(RemoteModel.NO_UUID), Task.UUID.isNull(), Task.UUID.eq("")));
|
||||
assertUUIDsExist(tasksQuery, new Task(), taskDao, taskOutstandingDao, new TaskOutstanding(), NameMaps.syncableProperties(NameMaps.TABLE_ID_TASKS), new UUIDAssertionExtras<Task>() {
|
||||
@Override
|
||||
public boolean shouldCreateOutstandingEntries(Task instance) {
|
||||
if (!instance.containsNonNullValue(Task.MODIFICATION_DATE) || instance.getValue(Task.LAST_SYNC) == 0) {
|
||||
return RemoteModelDao.getOutstandingEntryFlag(RemoteModelDao.OUTSTANDING_ENTRY_FLAG_RECORD_OUTSTANDING);
|
||||
}
|
||||
|
||||
return (instance.getValue(Task.LAST_SYNC) < instance.getValue(Task.MODIFICATION_DATE)) && RemoteModelDao.getOutstandingEntryFlag(RemoteModelDao.OUTSTANDING_ENTRY_FLAG_RECORD_OUTSTANDING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterSave(Task instance, boolean createdOutstanding) {
|
||||
if (createdOutstanding) {
|
||||
tasksThatNeedTagSync.add(instance.getId());
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "Error asserting UUIDs", e);
|
||||
}
|
||||
|
||||
// --------------
|
||||
// Update task flags
|
||||
// --------------
|
||||
Task template = new Task();
|
||||
try {
|
||||
template.setValue(Task.IS_READONLY, 1);
|
||||
taskDao.update(Functions.bitwiseAnd(Task.FLAGS, Task.FLAG_IS_READONLY).gt(0), template);
|
||||
template.clear();
|
||||
template.setValue(Task.IS_PUBLIC, 1);
|
||||
taskDao.update(Functions.bitwiseAnd(Task.FLAGS, Task.FLAG_PUBLIC).gt(0), template);
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "Error clearing task flags", e);
|
||||
}
|
||||
|
||||
// --------------
|
||||
// Update recurrence values
|
||||
// --------------
|
||||
TodorooCursor<Task> tasksWithRecurrence = null;
|
||||
try {
|
||||
tasksWithRecurrence = taskDao.query(Query.select(Task.ID, Task.FLAGS, Task.RECURRENCE).where(Criterion.or(Task.RECURRENCE.isNotNull(), Task.RECURRENCE.neq(""))));
|
||||
for (tasksWithRecurrence.moveToFirst(); !tasksWithRecurrence.isAfterLast(); tasksWithRecurrence.moveToNext()) {
|
||||
try {
|
||||
template.clear();
|
||||
template.readFromCursor(tasksWithRecurrence);
|
||||
String recurrence = template.getValue(Task.RECURRENCE);
|
||||
if (!TextUtils.isEmpty(recurrence)) {
|
||||
String fromCompletion = ";FROM=COMPLETION";
|
||||
boolean repeatAfterCompletion = template.getFlag(Task.FLAGS, Task.FLAG_REPEAT_AFTER_COMPLETION);
|
||||
template.setFlag(Task.FLAGS, Task.FLAG_REPEAT_AFTER_COMPLETION, false);
|
||||
|
||||
recurrence = recurrence.replaceAll("BYDAY=;", "");
|
||||
if (fromCompletion.equals(recurrence)) {
|
||||
recurrence = "";
|
||||
} else if (repeatAfterCompletion) {
|
||||
recurrence = recurrence + fromCompletion;
|
||||
}
|
||||
template.setValue(Task.RECURRENCE, recurrence);
|
||||
|
||||
template.putTransitory(SyncFlags.GTASKS_SUPPRESS_SYNC, true);
|
||||
taskDao.saveExisting(template);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "Error migrating recurrence", e);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "Error migrating recurrence", e);
|
||||
} finally {
|
||||
if (tasksWithRecurrence != null) {
|
||||
tasksWithRecurrence.close();
|
||||
}
|
||||
}
|
||||
|
||||
// --------------
|
||||
// Migrate unsynced task comments to UserActivity table
|
||||
// --------------
|
||||
TodorooCursor<Update> updates = null;
|
||||
try {
|
||||
updates = updateDao.query(Query.select(Update.PROPERTIES).where(
|
||||
Criterion.and(Criterion.or(Update.REMOTE_ID.eq(0), Update.REMOTE_ID.isNull()), Criterion.or(Update.ACTION_CODE.eq(UserActivity.ACTION_TAG_COMMENT),
|
||||
Update.ACTION_CODE.eq(UserActivity.ACTION_TASK_COMMENT)))));
|
||||
Update update = new Update();
|
||||
UserActivity userActivity = new UserActivity();
|
||||
for (updates.moveToFirst(); !updates.isAfterLast(); updates.moveToNext()) {
|
||||
try {
|
||||
update.clear();
|
||||
userActivity.clear();
|
||||
|
||||
update.readFromCursor(updates);
|
||||
|
||||
boolean setTarget = true;
|
||||
if (!RemoteModel.isUuidEmpty(update.getValue(Update.TASK).toString())) {
|
||||
userActivity.setValue(UserActivity.TARGET_ID, update.getValue(Update.TASK).toString());
|
||||
} else if (update.getValue(Update.TASK_LOCAL) > 0) {
|
||||
Task local = taskDao.fetch(update.getValue(Update.TASK_LOCAL), Task.UUID);
|
||||
if (local != null && !RemoteModel.isUuidEmpty(local.getUuid())) {
|
||||
userActivity.setValue(UserActivity.TARGET_ID, local.getUuid());
|
||||
} else {
|
||||
setTarget = false;
|
||||
}
|
||||
} else {
|
||||
setTarget = false;
|
||||
}
|
||||
|
||||
if (setTarget) {
|
||||
userActivity.setValue(UserActivity.USER_UUID, update.getValue(Update.USER_ID).toString());
|
||||
userActivity.setValue(UserActivity.ACTION, update.getValue(Update.ACTION_CODE));
|
||||
userActivity.setValue(UserActivity.MESSAGE, update.getValue(Update.MESSAGE));
|
||||
userActivity.setValue(UserActivity.CREATED_AT, update.getValue(Update.CREATION_DATE));
|
||||
userActivityDao.createNew(userActivity);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "Error migrating updates", e);
|
||||
}
|
||||
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "Error migrating updates", e);
|
||||
} finally {
|
||||
if (updates != null) {
|
||||
updates.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// --------------
|
||||
// Drop any entries from the Users table that don't have a UUID
|
||||
// --------------
|
||||
try {
|
||||
userDao.deleteWhere(Criterion.or(User.UUID.isNull(), User.UUID.eq(""), User.UUID.eq("0")));
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "Error deleting incomplete user entries", e);
|
||||
}
|
||||
|
||||
// --------------
|
||||
// Migrate legacy FileMetadata models to new TaskAttachment models
|
||||
// --------------
|
||||
TodorooCursor<Metadata> fmCursor = null;
|
||||
try {
|
||||
fmCursor = metadataService.query(Query.select(Metadata.PROPERTIES)
|
||||
.where(MetadataCriteria.withKey(FileMetadata.METADATA_KEY)));
|
||||
Metadata m = new Metadata();
|
||||
TaskAttachment attachment = new TaskAttachment();
|
||||
for (fmCursor.moveToFirst(); !fmCursor.isAfterLast(); fmCursor.moveToNext()) {
|
||||
try {
|
||||
attachment.clear();
|
||||
m.clear();
|
||||
m.readFromCursor(fmCursor);
|
||||
|
||||
Task task = taskDao.fetch(m.getValue(Metadata.TASK), Task.UUID);
|
||||
if (task == null || !RemoteModel.isValidUuid(task.getUuid())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Long oldRemoteId = m.getValue(FileMetadata.REMOTE_ID);
|
||||
boolean synced = false;
|
||||
if (oldRemoteId != null && oldRemoteId > 0) {
|
||||
synced = true;
|
||||
attachment.setValue(TaskAttachment.UUID, Long.toString(oldRemoteId));
|
||||
}
|
||||
attachment.setValue(TaskAttachment.TASK_UUID, task.getUuid());
|
||||
if (m.containsNonNullValue(FileMetadata.NAME)) {
|
||||
attachment.setValue(TaskAttachment.NAME, m.getValue(FileMetadata.NAME));
|
||||
}
|
||||
if (m.containsNonNullValue(FileMetadata.URL)) {
|
||||
attachment.setValue(TaskAttachment.URL, m.getValue(FileMetadata.URL));
|
||||
}
|
||||
if (m.containsNonNullValue(FileMetadata.FILE_PATH)) {
|
||||
attachment.setValue(TaskAttachment.FILE_PATH, m.getValue(FileMetadata.FILE_PATH));
|
||||
}
|
||||
if (m.containsNonNullValue(FileMetadata.FILE_TYPE)) {
|
||||
attachment.setValue(TaskAttachment.CONTENT_TYPE, m.getValue(FileMetadata.FILE_TYPE));
|
||||
}
|
||||
if (m.containsNonNullValue(FileMetadata.DELETION_DATE)) {
|
||||
attachment.setValue(TaskAttachment.DELETED_AT, m.getValue(FileMetadata.DELETION_DATE));
|
||||
}
|
||||
|
||||
if (synced) {
|
||||
attachment.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true);
|
||||
}
|
||||
|
||||
if (!ActFmPreferenceService.isPremiumUser()) {
|
||||
attachment.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true);
|
||||
}
|
||||
taskAttachmentDao.createNew(attachment);
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "Error migrating task attachment metadata", e);
|
||||
}
|
||||
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "Error migrating task attachment metadata", e);
|
||||
} finally {
|
||||
if (fmCursor != null) {
|
||||
fmCursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
// --------------
|
||||
// Create task list metadata entries for each tag
|
||||
// --------------
|
||||
TaskListMetadata tlm = new TaskListMetadata();
|
||||
try {
|
||||
String activeTasksOrder = Preferences.getStringValue(SubtasksUpdater.ACTIVE_TASKS_ORDER);
|
||||
if (TextUtils.isEmpty(activeTasksOrder)) {
|
||||
activeTasksOrder = "[]";
|
||||
}
|
||||
|
||||
activeTasksOrder = SubtasksHelper.convertTreeToRemoteIds(activeTasksOrder);
|
||||
|
||||
tlm.setValue(TaskListMetadata.FILTER, TaskListMetadata.FILTER_ID_ALL);
|
||||
tlm.setValue(TaskListMetadata.TASK_IDS, activeTasksOrder);
|
||||
if (taskListMetadataDao.update(TaskListMetadata.FILTER.eq(TaskListMetadata.FILTER_ID_ALL), tlm) <= 0) {
|
||||
taskListMetadataDao.createNew(tlm);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "Error migrating active tasks ordering", e);
|
||||
}
|
||||
|
||||
try {
|
||||
tlm.clear();
|
||||
String todayTasksOrder = Preferences.getStringValue(SubtasksUpdater.TODAY_TASKS_ORDER);
|
||||
if (TextUtils.isEmpty(todayTasksOrder)) {
|
||||
todayTasksOrder = "[]";
|
||||
}
|
||||
|
||||
todayTasksOrder = SubtasksHelper.convertTreeToRemoteIds(todayTasksOrder);
|
||||
|
||||
tlm.setValue(TaskListMetadata.FILTER, TaskListMetadata.FILTER_ID_TODAY);
|
||||
tlm.setValue(TaskListMetadata.TASK_IDS, todayTasksOrder);
|
||||
if (taskListMetadataDao.update(TaskListMetadata.FILTER.eq(TaskListMetadata.FILTER_ID_TODAY), tlm) <= 0) {
|
||||
taskListMetadataDao.createNew(tlm);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "Error migrating today ordering", e);
|
||||
}
|
||||
|
||||
TodorooCursor<TagData> allTagData = null;
|
||||
try {
|
||||
allTagData = tagDataDao.query(Query.select(TagData.ID, TagData.UUID, TagData.TAG_ORDERING));
|
||||
TagData td = new TagData();
|
||||
for (allTagData.moveToFirst(); !allTagData.isAfterLast(); allTagData.moveToNext()) {
|
||||
try {
|
||||
tlm.clear();
|
||||
td.clear();
|
||||
|
||||
td.readFromCursor(allTagData);
|
||||
String tagOrdering = td.getValue(TagData.TAG_ORDERING);
|
||||
tagOrdering = SubtasksHelper.convertTreeToRemoteIds(tagOrdering);
|
||||
|
||||
tlm.setValue(TaskListMetadata.TASK_IDS, tagOrdering);
|
||||
tlm.setValue(TaskListMetadata.TAG_UUID, td.getUuid());
|
||||
taskListMetadataDao.createNew(tlm);
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "Error migrating tag ordering", e);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "Error migrating tag ordering", e);
|
||||
} finally {
|
||||
if (allTagData != null) {
|
||||
allTagData.close();
|
||||
}
|
||||
}
|
||||
|
||||
// --------------
|
||||
// Ensure that all tag metadata entities have all important fields filled in
|
||||
// --------------
|
||||
TodorooCursor<Metadata> incompleteMetadata = null;
|
||||
try {
|
||||
Query incompleteQuery = Query.select(Metadata.PROPERTIES).where(Criterion.and(
|
||||
MetadataCriteria.withKey(TaskToTagMetadata.KEY),
|
||||
Criterion.or(TaskToTagMetadata.TASK_UUID.eq(0), TaskToTagMetadata.TASK_UUID.isNull(),
|
||||
TaskToTagMetadata.TAG_UUID.eq(0), TaskToTagMetadata.TAG_UUID.isNull())));
|
||||
incompleteMetadata = metadataService.query(incompleteQuery);;
|
||||
Metadata m = new Metadata();
|
||||
for (incompleteMetadata.moveToFirst(); !incompleteMetadata.isAfterLast(); incompleteMetadata.moveToNext()) {
|
||||
try {
|
||||
m.clear(); // Need this since some properties may be null
|
||||
m.readFromCursor(incompleteMetadata);
|
||||
|
||||
if (ActFmInvoker.SYNC_DEBUG) {
|
||||
Log.w(LOG_TAG, "Incomplete linking task " + m.getValue(Metadata.TASK) + " to " + m.getValue(TaskToTagMetadata.TAG_NAME));
|
||||
}
|
||||
|
||||
if (!m.containsNonNullValue(TaskToTagMetadata.TASK_UUID) || RemoteModel.isUuidEmpty(m.getValue(TaskToTagMetadata.TASK_UUID))) {
|
||||
if (ActFmInvoker.SYNC_DEBUG) {
|
||||
Log.w(LOG_TAG, "No task uuid");
|
||||
}
|
||||
updateTaskUuid(m);
|
||||
}
|
||||
|
||||
if (!m.containsNonNullValue(TaskToTagMetadata.TAG_UUID) || RemoteModel.isUuidEmpty(m.getValue(TaskToTagMetadata.TAG_UUID))) {
|
||||
if (ActFmInvoker.SYNC_DEBUG) {
|
||||
Log.w(LOG_TAG, "No tag uuid");
|
||||
}
|
||||
updateTagUuid(m);
|
||||
}
|
||||
|
||||
if (m.getSetValues() != null && m.getSetValues().size() > 0) {
|
||||
metadataService.save(m);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "Error validating task to tag metadata", e);
|
||||
}
|
||||
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "Error validating task to tag metadata", e);
|
||||
} finally {
|
||||
if (incompleteMetadata != null) {
|
||||
incompleteMetadata.close();
|
||||
}
|
||||
}
|
||||
|
||||
// --------------
|
||||
// Delete all featured list data
|
||||
// --------------
|
||||
try {
|
||||
tagDataDao.deleteWhere(Functions.bitwiseAnd(TagData.FLAGS, TagData.FLAG_FEATURED).gt(0));
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "Error deleting featured list data", e);
|
||||
}
|
||||
|
||||
|
||||
// --------------
|
||||
// Finally, create oustanding entries for tags on unsynced tasks
|
||||
// --------------
|
||||
TodorooCursor<Metadata> tagsAdded = null;
|
||||
try {
|
||||
Long[] ids = tasksThatNeedTagSync.toArray(new Long[tasksThatNeedTagSync.size()]);
|
||||
tagsAdded = metadataService.query(Query.select(Metadata.PROPERTIES)
|
||||
.where(Criterion.and(MetadataCriteria.withKey(TaskToTagMetadata.KEY), Metadata.TASK.in(ids))).orderBy(Order.asc(Metadata.TASK)));
|
||||
Metadata m = new Metadata();
|
||||
for (tagsAdded.moveToFirst(); !tagsAdded.isAfterLast(); tagsAdded.moveToNext()) {
|
||||
try {
|
||||
m.clear();
|
||||
m.readFromCursor(tagsAdded);
|
||||
Long deletionDate = m.getValue(Metadata.DELETION_DATE);
|
||||
String tagUuid = m.getValue(TaskToTagMetadata.TAG_UUID);
|
||||
if (!RemoteModel.isValidUuid(tagUuid)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TaskOutstanding to = new TaskOutstanding();
|
||||
to.setValue(OutstandingEntry.ENTITY_ID_PROPERTY, m.getValue(Metadata.TASK));
|
||||
to.setValue(OutstandingEntry.CREATED_AT_PROPERTY, DateUtilities.now());
|
||||
String addedOrRemoved = NameMaps.TAG_ADDED_COLUMN;
|
||||
if (deletionDate != null && deletionDate > 0) {
|
||||
addedOrRemoved = NameMaps.TAG_REMOVED_COLUMN;
|
||||
}
|
||||
|
||||
to.setValue(OutstandingEntry.COLUMN_STRING_PROPERTY, addedOrRemoved);
|
||||
to.setValue(OutstandingEntry.VALUE_STRING_PROPERTY, tagUuid);
|
||||
taskOutstandingDao.createNew(to);
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "Error creating tag_added outstanding entries", e);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "Error creating tag_added outstanding entries", e);
|
||||
} finally {
|
||||
if (tagsAdded != null) {
|
||||
tagsAdded.close();
|
||||
}
|
||||
}
|
||||
|
||||
Preferences.setBoolean(PREF_SYNC_MIGRATION, true);
|
||||
ActFmSyncMonitor monitor = ActFmSyncMonitor.getInstance();
|
||||
synchronized (monitor) {
|
||||
monitor.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
private interface UUIDAssertionExtras<TYPE extends RemoteModel> {
|
||||
boolean shouldCreateOutstandingEntries(TYPE instance);
|
||||
void afterSave(TYPE instance, boolean createdOutstanding);
|
||||
}
|
||||
|
||||
private <TYPE extends RemoteModel, OE extends OutstandingEntry<TYPE>> void assertUUIDsExist(Query query, TYPE instance, DatabaseDao<TYPE> dao, OutstandingEntryDao<OE> oeDao, OE oe, Property<?>[] propertiesForOutstanding, UUIDAssertionExtras<TYPE> extras) {
|
||||
TodorooCursor<TYPE> cursor = null;
|
||||
try {
|
||||
cursor = dao.query(query);
|
||||
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
|
||||
try {
|
||||
instance.clear();
|
||||
instance.readPropertiesFromCursor(cursor);
|
||||
boolean unsyncedModel = false;
|
||||
if (!instance.containsNonNullValue(RemoteModel.UUID_PROPERTY) || RemoteModel.NO_UUID.equals(instance.getValue(RemoteModel.UUID_PROPERTY)) ||
|
||||
"".equals(instance.getValue(RemoteModel.UUID_PROPERTY)) || "null".equals(instance.getValue(RemoteModel.UUID_PROPERTY))) {
|
||||
// No remote id exists, just create a UUID
|
||||
unsyncedModel = true;
|
||||
instance.setValue(RemoteModel.UUID_PROPERTY, UUIDHelper.newUUID());
|
||||
}
|
||||
|
||||
instance.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true);
|
||||
instance.putTransitory(SyncFlags.GTASKS_SUPPRESS_SYNC, true);
|
||||
dao.saveExisting(instance);
|
||||
boolean createdOutstanding = false;
|
||||
if (propertiesForOutstanding != null && (unsyncedModel || (extras != null && extras.shouldCreateOutstandingEntries(instance)))) {
|
||||
createdOutstanding = true;
|
||||
createOutstandingEntries(instance.getId(), dao, oeDao, oe, propertiesForOutstanding);
|
||||
}
|
||||
if (extras != null) {
|
||||
extras.afterSave(instance, createdOutstanding);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "Error asserting UUIDs", e);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "Error asserting UUIDs", e);
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private <TYPE extends RemoteModel, OE extends OutstandingEntry<TYPE>> void createOutstandingEntries(long id, DatabaseDao<TYPE> dao, OutstandingEntryDao<OE> oeDao, OE oe, Property<?>[] propertiesForOutstanding) {
|
||||
TYPE instance = dao.fetch(id, propertiesForOutstanding);
|
||||
long now = DateUtilities.now();
|
||||
for (Property<?> property : propertiesForOutstanding) {
|
||||
oe.clear();
|
||||
oe.setValue(OutstandingEntry.ENTITY_ID_PROPERTY, id);
|
||||
oe.setValue(OutstandingEntry.COLUMN_STRING_PROPERTY, property.name);
|
||||
Object value = instance.getValue(property);
|
||||
if (value == null) {
|
||||
value = "";
|
||||
}
|
||||
oe.setValue(OutstandingEntry.VALUE_STRING_PROPERTY, value.toString());
|
||||
oe.setValue(OutstandingEntry.CREATED_AT_PROPERTY, now);
|
||||
oeDao.createNew(oe);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTaskUuid(Metadata m) {
|
||||
long taskId = m.getValue(Metadata.TASK);
|
||||
Task task = taskDao.fetch(taskId, Task.UUID);
|
||||
if (task != null) {
|
||||
if (ActFmInvoker.SYNC_DEBUG) {
|
||||
Log.w(LOG_TAG, "Linking with task uuid " + task.getValue(Task.UUID));
|
||||
}
|
||||
m.setValue(TaskToTagMetadata.TASK_UUID, task.getValue(Task.UUID));
|
||||
} else {
|
||||
if (ActFmInvoker.SYNC_DEBUG) {
|
||||
Log.w(LOG_TAG, "Task not found, deleting link");
|
||||
}
|
||||
m.setValue(Metadata.DELETION_DATE, DateUtilities.now());
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTagUuid(Metadata m) {
|
||||
String tag = m.getValue(TaskToTagMetadata.TAG_NAME);
|
||||
TagData tagData = tagDataService.getTagByName(tag, TagData.UUID);
|
||||
if (tagData != null) {
|
||||
if (ActFmInvoker.SYNC_DEBUG) {
|
||||
Log.w(LOG_TAG, "Linking with tag uuid " + tagData.getValue(TagData.UUID));
|
||||
}
|
||||
m.setValue(TaskToTagMetadata.TAG_UUID, tagData.getValue(TagData.UUID));
|
||||
} else {
|
||||
if (ActFmInvoker.SYNC_DEBUG) {
|
||||
Log.w(LOG_TAG, "Tag not found, deleting link");
|
||||
}
|
||||
m.setValue(Metadata.DELETION_DATE, DateUtilities.now());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue