diff --git a/app/src/androidTest/java/org/tasks/opentasks/OpenTasksSynchronizerTest.kt b/app/src/androidTest/java/org/tasks/opentasks/OpenTasksSynchronizerTest.kt index acd8ba3f5..3855f66ac 100644 --- a/app/src/androidTest/java/org/tasks/opentasks/OpenTasksSynchronizerTest.kt +++ b/app/src/androidTest/java/org/tasks/opentasks/OpenTasksSynchronizerTest.kt @@ -1,5 +1,7 @@ package org.tasks.opentasks +import com.natpryce.makeiteasy.MakeItEasy +import com.todoroo.astrid.helper.UUIDHelper import dagger.hilt.android.testing.HiltAndroidTest import dagger.hilt.android.testing.UninstallModules import kotlinx.coroutines.runBlocking @@ -10,9 +12,13 @@ import org.junit.Test import org.tasks.R import org.tasks.data.CaldavAccount import org.tasks.data.CaldavAccount.Companion.TYPE_OPENTASKS +import org.tasks.data.CaldavCalendar import org.tasks.data.CaldavDao +import org.tasks.data.TaskDao import org.tasks.injection.InjectingTestCase import org.tasks.injection.ProductionModule +import org.tasks.makers.CaldavTaskMaker +import org.tasks.makers.TaskMaker.newTask import org.tasks.preferences.Preferences import javax.inject.Inject @@ -23,6 +29,7 @@ class OpenTasksSynchronizerTest : InjectingTestCase() { @Inject lateinit var caldavDao: CaldavDao @Inject lateinit var synchronizer: OpenTasksSynchronizer @Inject lateinit var preferences: Preferences + @Inject lateinit var taskDao: TaskDao @Before override fun setUp() { @@ -84,4 +91,34 @@ class OpenTasksSynchronizerTest : InjectingTestCase() { assertEquals(name, "default_list") } } + + @Test + fun removeMissingLists() = runBlocking { + val (_, list) = openTaskDao.insertList(url = "url1") + caldavDao.insert(CaldavCalendar().apply { + account = list.account + uuid = UUIDHelper.newUUID() + url = "url2" + }) + + synchronizer.sync() + + assertEquals(listOf(list), caldavDao.getCalendars()) + } + + @Test + fun simplePushNewTask() = runBlocking { + val (_, list) = openTaskDao.insertList() + val taskId = taskDao.insert(newTask()) + caldavDao.insert(CaldavTaskMaker.newCaldavTask( + MakeItEasy.with(CaldavTaskMaker.CALENDAR, list.uuid), + MakeItEasy.with(CaldavTaskMaker.TASK, taskId) + )) + + synchronizer.sync() + + val tasks = openTaskDao.getTasks() + assertEquals(1, tasks.size) + assertEquals(taskId, caldavDao.getTaskByRemoteId(list.uuid!!, tasks[0].uid!!)?.task) + } } \ No newline at end of file diff --git a/app/src/androidTest/java/org/tasks/opentasks/TestOpenTaskDao.kt b/app/src/androidTest/java/org/tasks/opentasks/TestOpenTaskDao.kt index 5f043509e..1b4e53e61 100644 --- a/app/src/androidTest/java/org/tasks/opentasks/TestOpenTaskDao.kt +++ b/app/src/androidTest/java/org/tasks/opentasks/TestOpenTaskDao.kt @@ -3,6 +3,7 @@ package org.tasks.opentasks import android.content.ContentProviderResult import android.content.Context import at.bitfire.ical4android.BatchOperation +import at.bitfire.ical4android.Task import com.todoroo.astrid.helper.UUIDHelper import dagger.hilt.android.qualifiers.ApplicationContext import org.dmfs.tasks.contract.TaskContract @@ -20,9 +21,9 @@ class TestOpenTaskDao @Inject constructor( suspend fun insertList( name: String = DEFAULT_LIST, type: String = DEFAULT_TYPE, - account: String = DEFAULT_ACCOUNT + account: String = DEFAULT_ACCOUNT, + url: String = UUIDHelper.newUUID(), ): Pair { - val url = UUIDHelper.newUUID() val uri = taskLists.buildUpon() .appendQueryParameter(TaskContract.CALLER_IS_SYNCADAPTER, "true") .appendQueryParameter(TaskContract.TaskLists.ACCOUNT_NAME, account) @@ -36,6 +37,7 @@ class TestOpenTaskDao @Inject constructor( ) return Pair(result.uri!!.lastPathSegment!!, CaldavCalendar().apply { uuid = UUIDHelper.newUUID() + this.name = name this.account = "$type:$account" this.url = url caldavDao.insert(this) @@ -50,6 +52,21 @@ class TestOpenTaskDao @Inject constructor( ) } + fun getTasks(): List { + val result = ArrayList() + cr.query( + tasks.buildUpon().appendQueryParameter(TaskContract.LOAD_PROPERTIES, "1").build(), + null, + null, + null, + null)?.use { + while (it.moveToNext()) { + MyAndroidTask(it).task?.let { task -> result.add(task) } + } + } + return result + } + fun reset( type: String = DEFAULT_TYPE, account: String = DEFAULT_ACCOUNT diff --git a/app/src/main/java/org/tasks/data/OpenTaskDao.kt b/app/src/main/java/org/tasks/data/OpenTaskDao.kt index b18b40503..a59b6740f 100644 --- a/app/src/main/java/org/tasks/data/OpenTaskDao.kt +++ b/app/src/main/java/org/tasks/data/OpenTaskDao.kt @@ -15,13 +15,17 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import net.fortuna.ical4j.model.property.XProperty import org.dmfs.tasks.contract.TaskContract.* +import org.dmfs.tasks.contract.TaskContract.Properties import org.dmfs.tasks.contract.TaskContract.Property.Category import org.dmfs.tasks.contract.TaskContract.Property.Relation import org.json.JSONObject import org.tasks.R import org.tasks.caldav.iCalendar.Companion.APPLE_SORT_ORDER +import org.tasks.data.CaldavAccount.Companion.openTaskType import timber.log.Timber +import java.util.* import javax.inject.Inject +import kotlin.collections.ArrayList open class OpenTaskDao @Inject constructor( @ApplicationContext context: Context, @@ -238,5 +242,18 @@ open class OpenTaskDao @Inject constructor( private fun Cursor.getLong(columnName: String): Long = getLong(getColumnIndex(columnName)) + + fun CaldavCalendar.toLocalCalendar(): CaldavCalendar { + val remote = this + return CaldavCalendar().apply { + uuid = UUID + .nameUUIDFromBytes("${account.openTaskType()}${remote.url}".toByteArray()) + .toString() + url = remote.url + color = remote.color + name = remote.name + account = remote.account + } + } } } \ No newline at end of file diff --git a/app/src/main/java/org/tasks/opentasks/OpenTasksSynchronizer.kt b/app/src/main/java/org/tasks/opentasks/OpenTasksSynchronizer.kt index 03d9feb54..4d60ea03a 100644 --- a/app/src/main/java/org/tasks/opentasks/OpenTasksSynchronizer.kt +++ b/app/src/main/java/org/tasks/opentasks/OpenTasksSynchronizer.kt @@ -4,6 +4,7 @@ import android.content.ContentProviderOperation import android.content.Context import com.todoroo.astrid.dao.TaskDao import com.todoroo.astrid.data.Task +import com.todoroo.astrid.data.Task.Companion.NO_ID import com.todoroo.astrid.service.TaskDeleter import dagger.hilt.android.qualifiers.ApplicationContext import org.dmfs.tasks.contract.TaskContract.Tasks @@ -14,11 +15,11 @@ import org.tasks.analytics.Firebase import org.tasks.billing.Inventory import org.tasks.caldav.iCalendar import org.tasks.data.* -import org.tasks.data.CaldavAccount.Companion.openTaskType import org.tasks.data.OpenTaskDao.Companion.isDavx5 import org.tasks.data.OpenTaskDao.Companion.isDecSync import org.tasks.data.OpenTaskDao.Companion.isEteSync import org.tasks.data.OpenTaskDao.Companion.newAccounts +import org.tasks.data.OpenTaskDao.Companion.toLocalCalendar import timber.log.Timber import java.util.* import javax.inject.Inject @@ -84,23 +85,19 @@ class OpenTasksSynchronizer @Inject constructor( .findDeletedCalendars(uuid, lists.mapNotNull { it.url }) .forEach { taskDeleter.delete(it) } lists.forEach { - val calendar = toLocalCalendar(uuid, it) + val calendar = toLocalCalendar(it) sync(account, calendar, it.ctag, it.id) } } - private suspend fun toLocalCalendar(account: String, remote: CaldavCalendar): CaldavCalendar { - val local = caldavDao.getCalendarByUrl(account, remote.url!!) - ?: CaldavCalendar().apply { - uuid = UUID - .nameUUIDFromBytes("${account.openTaskType()}${remote.url}".toByteArray()) - .toString() - url = remote.url - this.account = account - caldavDao.insert(this) - Timber.d("Created calendar: $this") - } - if (local.name != remote.name || local.color != remote.color) { + private suspend fun toLocalCalendar(remote: CaldavCalendar): CaldavCalendar { + val local = caldavDao.getCalendarByUrl(remote.account!!, remote.url!!) + ?: remote.toLocalCalendar() + if (local.id == NO_ID) { + caldavDao.insert(local) + Timber.d("Created calendar: $local") + localBroadcastManager.broadcastRefreshList() + } else if (local.name != remote.name || local.color != remote.color) { local.color = remote.color local.name = remote.name caldavDao.update(local)