mirror of https://github.com/tasks/tasks
Add MicrosoftConverter
parent
dd48d074be
commit
f38b2324e9
@ -0,0 +1,78 @@
|
|||||||
|
package org.tasks.sync.microsoft
|
||||||
|
|
||||||
|
import com.todoroo.astrid.data.Task
|
||||||
|
import org.tasks.data.CaldavTask
|
||||||
|
import org.tasks.data.TagData
|
||||||
|
import org.tasks.time.DateTime
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
object MicrosoftConverter {
|
||||||
|
|
||||||
|
private const val TYPE_TEXT = "text"
|
||||||
|
|
||||||
|
fun Task.applyRemote(
|
||||||
|
remote: Tasks.Task,
|
||||||
|
defaultPriority: Int,
|
||||||
|
) {
|
||||||
|
title = remote.title
|
||||||
|
notes = remote.body?.content?.takeIf { it.isNotBlank() }
|
||||||
|
priority = when {
|
||||||
|
remote.importance == Tasks.Task.Importance.high -> Task.Priority.HIGH
|
||||||
|
priority != Task.Priority.HIGH -> priority
|
||||||
|
defaultPriority != Task.Priority.HIGH -> defaultPriority
|
||||||
|
else -> Task.Priority.NONE
|
||||||
|
}
|
||||||
|
completionDate = remote.completedDateTime
|
||||||
|
?.let {
|
||||||
|
val tz = TimeZone.getTimeZone(it.timeZone)
|
||||||
|
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.ssssss")
|
||||||
|
.apply { timeZone = tz }
|
||||||
|
.parse(it.dateTime)
|
||||||
|
?.time
|
||||||
|
?.let { ts -> DateTime(ts, tz).toLocal().millis }
|
||||||
|
?: System.currentTimeMillis()
|
||||||
|
}
|
||||||
|
?: 0L
|
||||||
|
// checklist to subtasks
|
||||||
|
// due date
|
||||||
|
// repeat
|
||||||
|
// modification date
|
||||||
|
// creation date
|
||||||
|
// sync reminders
|
||||||
|
// sync files
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Task.toRemote(caldavTask: CaldavTask, tags: List<TagData>): Tasks.Task {
|
||||||
|
return Tasks.Task(
|
||||||
|
id = caldavTask.remoteId,
|
||||||
|
title = title,
|
||||||
|
body = notes?.let {
|
||||||
|
Tasks.Task.Body(
|
||||||
|
content = it,
|
||||||
|
contentType = TYPE_TEXT,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
importance = when (priority) {
|
||||||
|
Task.Priority.HIGH -> Tasks.Task.Importance.high
|
||||||
|
Task.Priority.MEDIUM -> Tasks.Task.Importance.normal
|
||||||
|
else -> Tasks.Task.Importance.low
|
||||||
|
},
|
||||||
|
status = if (isCompleted) {
|
||||||
|
Tasks.Task.Status.completed
|
||||||
|
} else {
|
||||||
|
Tasks.Task.Status.notStarted
|
||||||
|
},
|
||||||
|
categories = tags.map { it.name!! }.takeIf { it.isNotEmpty() },
|
||||||
|
completedDateTime = if (isCompleted) {
|
||||||
|
Tasks.Task.CompletedDateTime(
|
||||||
|
dateTime = DateTime(completionDate).toUTC()
|
||||||
|
.toString("yyyy-MM-dd'T'HH:mm:ss.SSSSSSS"),
|
||||||
|
timeZone = "UTC",
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,65 @@
|
|||||||
|
package org.tasks.sync.microsoft
|
||||||
|
|
||||||
|
import com.natpryce.makeiteasy.MakeItEasy
|
||||||
|
import com.todoroo.astrid.data.Task
|
||||||
|
import org.junit.Assert
|
||||||
|
import org.junit.Test
|
||||||
|
import org.tasks.TestUtilities
|
||||||
|
import org.tasks.makers.TaskMaker
|
||||||
|
import org.tasks.time.DateTime
|
||||||
|
|
||||||
|
class ConvertFromMicrosoftTests {
|
||||||
|
@Test
|
||||||
|
fun titleFromRemote() {
|
||||||
|
val (local, _) = TestUtilities.mstodo("microsoft/basic_task.txt")
|
||||||
|
Assert.assertEquals("Basic task", local.title)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun useNullForBlankBody() {
|
||||||
|
val (local, _) = TestUtilities.mstodo("microsoft/basic_task.txt")
|
||||||
|
Assert.assertNull(local.notes)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun keepPriority() {
|
||||||
|
val (local, _) = TestUtilities.mstodo(
|
||||||
|
"microsoft/basic_task.txt",
|
||||||
|
task = TaskMaker.newTask(MakeItEasy.with(TaskMaker.PRIORITY, Task.Priority.MEDIUM)),
|
||||||
|
defaultPriority = Task.Priority.LOW
|
||||||
|
)
|
||||||
|
Assert.assertEquals(Task.Priority.MEDIUM, local.priority)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun useDefaultPriority() {
|
||||||
|
val (local, _) = TestUtilities.mstodo(
|
||||||
|
"microsoft/basic_task.txt",
|
||||||
|
task = TaskMaker.newTask(MakeItEasy.with(TaskMaker.PRIORITY, Task.Priority.HIGH)),
|
||||||
|
defaultPriority = Task.Priority.LOW
|
||||||
|
)
|
||||||
|
Assert.assertEquals(Task.Priority.LOW, local.priority)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun noPriorityWhenDefaultIsHigh() {
|
||||||
|
val (local, _) = TestUtilities.mstodo(
|
||||||
|
"microsoft/basic_task.txt",
|
||||||
|
task = TaskMaker.newTask(MakeItEasy.with(TaskMaker.PRIORITY, Task.Priority.HIGH)),
|
||||||
|
defaultPriority = Task.Priority.HIGH
|
||||||
|
)
|
||||||
|
Assert.assertEquals(Task.Priority.NONE, local.priority)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun noCompletionDate() {
|
||||||
|
val (local, _) = TestUtilities.mstodo("microsoft/basic_task.txt")
|
||||||
|
Assert.assertEquals(0, local.completionDate)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun parseCompletionDate() {
|
||||||
|
val (local, _) = TestUtilities.mstodo("microsoft/completed_task.txt")
|
||||||
|
Assert.assertEquals(DateTime(2022, 9, 18, 0, 0).millis, local.completionDate)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,115 @@
|
|||||||
|
package org.tasks.sync.microsoft
|
||||||
|
|
||||||
|
import com.natpryce.makeiteasy.MakeItEasy.with
|
||||||
|
import com.todoroo.astrid.data.Task
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertNull
|
||||||
|
import org.junit.Test
|
||||||
|
import org.tasks.makers.CaldavTaskMaker.REMOTE_ID
|
||||||
|
import org.tasks.makers.CaldavTaskMaker.newCaldavTask
|
||||||
|
import org.tasks.makers.TagDataMaker.NAME
|
||||||
|
import org.tasks.makers.TagDataMaker.newTagData
|
||||||
|
import org.tasks.makers.TaskMaker.COMPLETION_TIME
|
||||||
|
import org.tasks.makers.TaskMaker.DESCRIPTION
|
||||||
|
import org.tasks.makers.TaskMaker.PRIORITY
|
||||||
|
import org.tasks.makers.TaskMaker.TITLE
|
||||||
|
import org.tasks.makers.TaskMaker.newTask
|
||||||
|
import org.tasks.sync.microsoft.MicrosoftConverter.toRemote
|
||||||
|
import org.tasks.sync.microsoft.Tasks.Task.Importance
|
||||||
|
import org.tasks.time.DateTime
|
||||||
|
|
||||||
|
class ConvertToMicrosoftTests {
|
||||||
|
@Test
|
||||||
|
fun noIdForNewTask() {
|
||||||
|
val remote =
|
||||||
|
newTask().toRemote(newCaldavTask(with(REMOTE_ID, null as String?)), emptyList())
|
||||||
|
assertNull(remote.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun setTitle() {
|
||||||
|
val remote =
|
||||||
|
newTask(with(TITLE, "title")).toRemote(newCaldavTask(), emptyList())
|
||||||
|
assertEquals("title", remote.title)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun noBody() {
|
||||||
|
val remote =
|
||||||
|
newTask(with(DESCRIPTION, null as String?))
|
||||||
|
.toRemote(newCaldavTask(), emptyList())
|
||||||
|
assertNull(remote.body)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun setBody() {
|
||||||
|
val remote =
|
||||||
|
newTask(with(DESCRIPTION, "Description"))
|
||||||
|
.toRemote(newCaldavTask(), emptyList())
|
||||||
|
assertEquals("Description", remote.body?.content)
|
||||||
|
assertEquals("text", remote.body?.contentType)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun setHighPriority() {
|
||||||
|
val remote =
|
||||||
|
newTask(with(PRIORITY, Task.Priority.HIGH))
|
||||||
|
.toRemote(newCaldavTask(), emptyList())
|
||||||
|
assertEquals(Importance.high, remote.importance)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun setNormalPriority() {
|
||||||
|
val remote =
|
||||||
|
newTask(with(PRIORITY, Task.Priority.MEDIUM))
|
||||||
|
.toRemote(newCaldavTask(), emptyList())
|
||||||
|
assertEquals(Importance.normal, remote.importance)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun setLowPriority() {
|
||||||
|
val remote =
|
||||||
|
newTask(with(PRIORITY, Task.Priority.LOW))
|
||||||
|
.toRemote(newCaldavTask(), emptyList())
|
||||||
|
assertEquals(Importance.low, remote.importance)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun setNoPriorityToLow() {
|
||||||
|
val remote =
|
||||||
|
newTask(with(PRIORITY, Task.Priority.NONE))
|
||||||
|
.toRemote(newCaldavTask(), emptyList())
|
||||||
|
assertEquals(Importance.low, remote.importance)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun statusForUncompletedTask() {
|
||||||
|
val remote = newTask().toRemote(newCaldavTask(), emptyList())
|
||||||
|
assertEquals(Tasks.Task.Status.notStarted, remote.status)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun statusForCompletedTask() {
|
||||||
|
val remote =
|
||||||
|
newTask(with(COMPLETION_TIME, DateTime())).toRemote(newCaldavTask(), emptyList())
|
||||||
|
assertEquals(Tasks.Task.Status.completed, remote.status)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun noCategories() {
|
||||||
|
val remote = newTask().toRemote(newCaldavTask(), emptyList())
|
||||||
|
assertNull(remote.categories)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun setCategories() {
|
||||||
|
val remote = newTask().toRemote(
|
||||||
|
newCaldavTask(),
|
||||||
|
listOf(
|
||||||
|
newTagData(with(NAME, "tag1")),
|
||||||
|
newTagData(with(NAME, "tag2")),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assertEquals(listOf("tag1", "tag2"), remote.categories)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#Collection(todoTask)",
|
||||||
|
"@odata.deltaLink": "https://graph.microsoft.com/v1.0/me/todo/lists/AQMkADAwATNiZmYAZC04OABiMC0xZDlkLTAwAi0wMAoALgAAA8dKmrSa60tBjeiKoPukmoQBAEkTxp6Wx2BEtV1vFJWK7bIAAAIBEgAAAA==/tasks/delta?$deltatoken=l7WI41swwioT5csv4k99nj_e6d30OPWG40P_OyQlkkny185Z38qUU3jLaP2oRC5t77tVxtd6SMRj0dEaTBh3MyHws0GnzQINZQHOs_ww6Z8.lmA23NEL8QGEOxyZEu-Uk2FszHDtjqkPsyfdoZaFIeE",
|
||||||
|
"value": [
|
||||||
|
{
|
||||||
|
"@odata.type": "#microsoft.graph.todoTask",
|
||||||
|
"@odata.etag": "W/\"SRPGnpbHYES1XW8UlYrtsgAFlRV2EQ==\"",
|
||||||
|
"importance": "normal",
|
||||||
|
"isReminderOn": false,
|
||||||
|
"status": "notStarted",
|
||||||
|
"title": "Basic task",
|
||||||
|
"createdDateTime": "2022-09-18T05:25:19.778574Z",
|
||||||
|
"lastModifiedDateTime": "2022-09-18T05:25:19.8723482Z",
|
||||||
|
"hasAttachments": false,
|
||||||
|
"categories": [],
|
||||||
|
"id": "AQMkADAwATNiZmYAZC04OABiMC0xZDlkLTAwAi0wMAoARgAAA8dKmrSa60tBjeiKoPukmoQHAEkTxp6Wx2BEtV1vFJWK7bIAAAIBEgAAAEkTxp6Wx2BEtV1vFJWK7bIABZUEdtwAAAA=",
|
||||||
|
"body": {
|
||||||
|
"content": "",
|
||||||
|
"contentType": "text"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#Collection(todoTask)",
|
||||||
|
"@odata.deltaLink": "https://graph.microsoft.com/v1.0/me/todo/lists/AQMkADAwATNiZmYAZC04OABiMC0xZDlkLTAwAi0wMAoALgAAA8dKmrSa60tBjeiKoPukmoQBAEkTxp6Wx2BEtV1vFJWK7bIAAAIBEgAAAA==/tasks/delta?$deltatoken=l7WI41swwioT5csv4k99nj_e6d30OPWG40P_OyQlkkny185Z38qUU3jLaP2oRC5tqLCV4OXibNfHoYNFTO2TnftnvrLwkmDPtGMUcu3SygY.rtzLcPg02xeQVyGPsoU5bQ8c2Nt8tY8ZhjhN1OUfJdQ",
|
||||||
|
"value": [
|
||||||
|
{
|
||||||
|
"@odata.type": "#microsoft.graph.todoTask",
|
||||||
|
"@odata.etag": "W/\"SRPGnpbHYES1XW8UlYrtsgAFlRV2eQ==\"",
|
||||||
|
"importance": "normal",
|
||||||
|
"isReminderOn": false,
|
||||||
|
"status": "completed",
|
||||||
|
"title": "Basic task",
|
||||||
|
"createdDateTime": "2022-09-18T05:25:19.778574Z",
|
||||||
|
"lastModifiedDateTime": "2022-09-18T06:25:27.6073845Z",
|
||||||
|
"hasAttachments": false,
|
||||||
|
"categories": [],
|
||||||
|
"id": "AQMkADAwATNiZmYAZC04OABiMC0xZDlkLTAwAi0wMAoARgAAA8dKmrSa60tBjeiKoPukmoQHAEkTxp6Wx2BEtV1vFJWK7bIAAAIBEgAAAEkTxp6Wx2BEtV1vFJWK7bIABZUEdtwAAAA=",
|
||||||
|
"body": {
|
||||||
|
"content": "",
|
||||||
|
"contentType": "text"
|
||||||
|
},
|
||||||
|
"completedDateTime": {
|
||||||
|
"dateTime": "2022-09-18T05:00:00.0000000",
|
||||||
|
"timeZone": "UTC"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue