feat(caldav): Add support for subtasks (i.e. RELATED-TO
property) in CalDAV (#1634)
As I mentioned [here](https://kolaente.dev/vikunja/api/pulls/1442#issuecomment-55215), this is mainly a cleanup of @zewaren 's original [PR](https://kolaente.dev/vikunja/api/pulls/1442). It adds support for the `RELATED-TO` property in CalDAV's `VTODO` and the `RELTYPE=PARENT` and `RELTYPE=CHILD` relationships. In other words, it allows for `ParentTask->SubTask` relations to be handled supported through CalDAV. In addition to the included tests, this has been tested by both @zewaren & myself with DAVx5 & Tasks (Android) and it's been working great. Resolves https://kolaente.dev/vikunja/api/issues/1345 Co-authored-by: Miguel A. Arroyo <miguel@codeheads.dev> Co-authored-by: Erwan Martin <public@fzwte.net> Reviewed-on: https://kolaente.dev/vikunja/api/pulls/1634 Reviewed-by: konrad <k@knt.li> Co-authored-by: Miguel Arroyo <mayanez@noreply.kolaente.de> Co-committed-by: Miguel Arroyo <mayanez@noreply.kolaente.de>
This commit is contained in:
@ -23,7 +23,6 @@ import (
|
||||
"time"
|
||||
|
||||
"code.vikunja.io/api/pkg/config"
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/log"
|
||||
"code.vikunja.io/api/pkg/models"
|
||||
"code.vikunja.io/api/pkg/utils"
|
||||
@ -51,6 +50,16 @@ func GetCaldavTodosForTasks(project *models.ProjectWithTasksAndBuckets, projectT
|
||||
})
|
||||
}
|
||||
|
||||
var relations []Relation
|
||||
for reltype, tasks := range t.RelatedTasks {
|
||||
for _, r := range tasks {
|
||||
relations = append(relations, Relation{
|
||||
Type: reltype,
|
||||
UID: r.UID,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
caldavtodos = append(caldavtodos, &Todo{
|
||||
Timestamp: t.Updated,
|
||||
UID: t.UID,
|
||||
@ -69,6 +78,7 @@ func GetCaldavTodosForTasks(project *models.ProjectWithTasksAndBuckets, projectT
|
||||
RepeatAfter: t.RepeatAfter,
|
||||
RepeatMode: t.RepeatMode,
|
||||
Alarms: alarms,
|
||||
Relations: relations,
|
||||
})
|
||||
}
|
||||
|
||||
@ -91,11 +101,11 @@ func ParseTaskFromVTODO(content string) (vTask *models.Task, err error) {
|
||||
}
|
||||
// We put the vTodo details in a map to be able to handle them more easily
|
||||
task := make(map[string]ics.IANAProperty)
|
||||
var relation ics.IANAProperty
|
||||
var relations []ics.IANAProperty
|
||||
for _, c := range vTodo.UnknownPropertiesIANAProperties() {
|
||||
task[c.IANAToken] = c
|
||||
if strings.HasPrefix(c.IANAToken, "RELATED-TO") {
|
||||
relation = c
|
||||
relations = append(relations, c)
|
||||
}
|
||||
}
|
||||
|
||||
@ -139,17 +149,33 @@ func ParseTaskFromVTODO(content string) (vTask *models.Task, err error) {
|
||||
DoneAt: caldavTimeToTimestamp(task["COMPLETED"]),
|
||||
}
|
||||
|
||||
if relation.Value != "" {
|
||||
s := db.NewSession()
|
||||
defer s.Close()
|
||||
for _, c := range relations {
|
||||
var relTypeStr string
|
||||
if _, ok := c.ICalParameters["RELTYPE"]; ok {
|
||||
if len(c.ICalParameters["RELTYPE"]) != 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
subtask, err := models.GetTaskSimpleByUUID(s, relation.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
relTypeStr = c.ICalParameters["RELTYPE"][0]
|
||||
}
|
||||
|
||||
vTask.RelatedTasks = make(map[models.RelationKind][]*models.Task)
|
||||
vTask.RelatedTasks[models.RelationKindSubtask] = []*models.Task{subtask}
|
||||
var relationKind models.RelationKind
|
||||
switch relTypeStr {
|
||||
case "PARENT":
|
||||
relationKind = models.RelationKindParenttask
|
||||
case "CHILD":
|
||||
relationKind = models.RelationKindSubtask
|
||||
default:
|
||||
relationKind = models.RelationKindParenttask
|
||||
}
|
||||
|
||||
if vTask.RelatedTasks == nil {
|
||||
vTask.RelatedTasks = make(map[models.RelationKind][]*models.Task)
|
||||
}
|
||||
|
||||
vTask.RelatedTasks[relationKind] = append(vTask.RelatedTasks[relationKind], &models.Task{
|
||||
UID: c.Value,
|
||||
})
|
||||
}
|
||||
|
||||
if task["STATUS"].Value == "COMPLETED" {
|
||||
|
Reference in New Issue
Block a user