Remove new sync migrator

pull/46/head
Alex Baker 12 years ago
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,19 +1,5 @@
package com.todoroo.astrid.actfm.sync;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.http.entity.mime.MultipartEntity;
import org.json.JSONArray;
import org.json.JSONObject;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
@ -25,7 +11,6 @@ import android.net.NetworkInfo;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import org.tasks.R;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.ContextManager;
@ -72,6 +57,21 @@ import com.todoroo.astrid.data.UserActivity;
import com.todoroo.astrid.utility.Constants;
import com.todoroo.astrid.widget.TasksWidget;
import org.apache.http.entity.mime.MultipartEntity;
import org.json.JSONArray;
import org.json.JSONObject;
import org.tasks.R;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class ActFmSyncThread {
private static final String ERROR_TAG = "actfm-sync-thread"; //$NON-NLS-1$
@ -113,8 +113,6 @@ public class ActFmSyncThread {
private String token;
private boolean syncMigration = false;
private boolean isTimeForBackgroundSync = false;
private final NotificationManager notificationManager;
@ -177,7 +175,6 @@ public class ActFmSyncThread {
this.pendingMessages = messageQueue;
this.pendingCallbacks = Collections.synchronizedMap(new HashMap<ClientToServerMessage<?>, SyncMessageCallback>());
this.monitor = syncMonitor;
this.syncMigration = Preferences.getBoolean(AstridNewSyncMigrator.PREF_SYNC_MIGRATION, false);
this.notificationManager = new AndroidNotificationManager(ContextManager.getContext());
}
@ -242,7 +239,7 @@ public class ActFmSyncThread {
List<ClientToServerMessage<?>> messageBatch = new ArrayList<ClientToServerMessage<?>>();
while(true) {
synchronized(monitor) {
while ((pendingMessages.isEmpty() && !timeForBackgroundSync()) || !actFmPreferenceService.isLoggedIn() || !syncMigration) {
while ((pendingMessages.isEmpty() && !timeForBackgroundSync()) || !actFmPreferenceService.isLoggedIn()) {
try {
if ((pendingMessages.isEmpty() || !actFmPreferenceService.isLoggedIn()) && notificationId >= 0) {
notificationManager.cancel(notificationId);
@ -250,10 +247,6 @@ public class ActFmSyncThread {
}
monitor.wait();
AndroidUtilities.sleepDeep(500L); // Wait briefly for large database operations to finish (e.g. adding a task with several tags may trigger a message before all saves are done--fix this?)
if (!syncMigration) {
syncMigration = Preferences.getBoolean(AstridNewSyncMigrator.PREF_SYNC_MIGRATION, false);
}
} catch (InterruptedException e) {
// Ignored
}

@ -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());
}
}
}

@ -5,9 +5,6 @@
*/
package com.todoroo.astrid.service;
import java.io.File;
import java.util.List;
import android.Manifest;
import android.app.Activity;
import android.app.AlarmManager;
@ -25,7 +22,6 @@ import android.media.AudioManager;
import android.util.Log;
import android.widget.Toast;
import org.tasks.R;
import com.todoroo.andlib.data.DatabaseDao.ModelUpdateListener;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.service.Autowired;
@ -40,7 +36,6 @@ import com.todoroo.andlib.utility.DialogUtilities;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.actfm.sync.ActFmSyncThread;
import com.todoroo.astrid.actfm.sync.AstridNewSyncMigrator;
import com.todoroo.astrid.activity.BeastModePreferences;
import com.todoroo.astrid.backup.BackupConstants;
import com.todoroo.astrid.backup.BackupService;
@ -70,6 +65,11 @@ import com.todoroo.astrid.utility.AstridPreferences;
import com.todoroo.astrid.utility.Constants;
import com.todoroo.astrid.widget.TasksWidget.WidgetUpdateService;
import org.tasks.R;
import java.io.File;
import java.util.List;
/**
* Service which handles jobs that need to be run when Astrid starts up.
*
@ -192,8 +192,6 @@ public class StartupService {
if(justUpgraded && version > 0) {
if(latestSetVersion > 0) {
upgradeService.performUpgrade(context, latestSetVersion);
} else {
Preferences.setBoolean(AstridNewSyncMigrator.PREF_SYNC_MIGRATION, true); // New installs should have this flag set up front
}
AstridPreferences.setCurrentVersion(version);
AstridPreferences.setCurrentVersionName(versionName);

@ -23,7 +23,6 @@ import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.andlib.utility.DialogUtilities;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.actfm.sync.AstridNewSyncMigrator;
import com.todoroo.astrid.actfm.sync.EmptyTitleOutstandingEntryMigration;
import com.todoroo.astrid.actfm.sync.messages.ConvertSelfUserIdsToZero;
import com.todoroo.astrid.actfm.sync.messages.NameMaps;
@ -237,7 +236,6 @@ public final class UpgradeService {
cursor.close();
}
}
new AstridNewSyncMigrator().performMigration();
}
if (from < V4_6_2) {

@ -2,18 +2,13 @@ package com.todoroo.astrid.subtasks;
import android.text.TextUtils;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.actfm.sync.AstridNewSyncMigrator;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.data.SyncFlags;
import com.todoroo.astrid.data.TaskListMetadata;
public class SubtasksFilterUpdater extends SubtasksUpdater<TaskListMetadata> {
private boolean migrationOccurred;
public SubtasksFilterUpdater() {
migrationOccurred = Preferences.getBoolean(AstridNewSyncMigrator.PREF_SYNC_MIGRATION, false);
}
@Override
@ -32,7 +27,7 @@ public class SubtasksFilterUpdater extends SubtasksUpdater<TaskListMetadata> {
@Override
protected void writeSerialization(TaskListMetadata list, String serialized, boolean shouldQueueSync) {
if (list != null && syncMigrationOccurred()) {
if (list != null) {
list.setValue(TaskListMetadata.TASK_IDS, serialized);
if (!shouldQueueSync) {
list.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true);
@ -40,13 +35,4 @@ public class SubtasksFilterUpdater extends SubtasksUpdater<TaskListMetadata> {
taskListMetadataDao.saveExisting(list);
}
}
private boolean syncMigrationOccurred() {
if (migrationOccurred) {
return true;
}
migrationOccurred = Preferences.getBoolean(AstridNewSyncMigrator.PREF_SYNC_MIGRATION, false);
return migrationOccurred;
}
}

Loading…
Cancel
Save