feat(caldav): CALDAV export subtask support

When exporting tasks in CALDAV, export attribute "Related-To" with the "PARENT" relationship, so that clients can display tasks with their proper hierarchy.
This commit is contained in:
Erwan Martin 2023-03-18 17:59:20 +01:00
parent 6aadaaaffc
commit c06f35e6a0
4 changed files with 186 additions and 26 deletions

View File

@ -51,20 +51,20 @@ type Todo struct {
UID string
// Optional
Summary string
Description string
Completed time.Time
Organizer *user.User
Priority int64 // 0-9, 1 is highest
RelatedToUID string
Color string
Categories []string
Start time.Time
End time.Time
DueDate time.Time
Duration time.Duration
RepeatAfter int64
RepeatMode models.TaskRepeatMode
Summary string
Description string
Completed time.Time
Organizer *user.User
Priority int64 // 0-9, 1 is highest
RelatedToParentUID string
Color string
Categories []string
Start time.Time
End time.Time
DueDate time.Time
Duration time.Duration
RepeatAfter int64
RepeatMode models.TaskRepeatMode
Created time.Time
Updated time.Time // last-mod
@ -209,9 +209,9 @@ STATUS:COMPLETED`
ORGANIZER;CN=:` + t.Organizer.Username
}
if t.RelatedToUID != "" {
if t.RelatedToParentUID != "" {
caldavtodos += `
RELATED-TO:` + t.RelatedToUID
RELATED-TO;RELTYPE=PARENT:` + t.RelatedToParentUID
}
if t.DueDate.Unix() > 0 {

View File

@ -520,6 +520,45 @@ X-FUNAMBOL-COLOR:#affffeFF
CATEGORIES:label1,label2
LAST-MODIFIED:00010101T000000Z
END:VTODO
END:VCALENDAR`,
},
{
name: "with parent task",
args: args{
config: &Config{
Name: "test",
ProdID: "RandomProdID which is not random",
Color: "ffffff",
},
todos: []*Todo{
{
Summary: "Todo #1",
UID: "randommduid",
Timestamp: time.Unix(1543626724, 0).In(config.GetTimeZone()),
Color: "affffe",
RelatedToParentUID: "another_random_uid",
},
},
},
wantCaldavtasks: `BEGIN:VCALENDAR
VERSION:2.0
METHOD:PUBLISH
X-PUBLISHED-TTL:PT4H
X-WR-CALNAME:test
PRODID:-//RandomProdID which is not random//EN
X-APPLE-CALENDAR-COLOR:#ffffffFF
X-OUTLOOK-COLOR:#ffffffFF
X-FUNAMBOL-COLOR:#ffffffFF
BEGIN:VTODO
UID:randommduid
DTSTAMP:20181201T011204Z
SUMMARY:Todo #1
X-APPLE-CALENDAR-COLOR:#affffeFF
X-OUTLOOK-COLOR:#affffeFF
X-FUNAMBOL-COLOR:#affffeFF
RELATED-TO;RELTYPE=PARENT:another_random_uid
LAST-MODIFIED:00010101T000000Z
END:VTODO
END:VCALENDAR`,
},
}

View File

@ -39,6 +39,12 @@ func GetCaldavTodosForTasks(project *models.ProjectWithTasksAndBuckets, projectT
categories = append(categories, label.Title)
}
// Find the UID of the parent task, if it exists:
var parentTaskUID string
if parentTasks, ok := t.RelatedTasks[models.RelationKindParenttask]; ok {
parentTaskUID = parentTasks[0].UID
}
caldavtodos = append(caldavtodos, &Todo{
Timestamp: t.Updated,
UID: t.UID,
@ -46,16 +52,17 @@ func GetCaldavTodosForTasks(project *models.ProjectWithTasksAndBuckets, projectT
Description: t.Description,
Completed: t.DoneAt,
// Organizer: &t.CreatedBy, // Disabled until we figure out how this works
Categories: categories,
Priority: t.Priority,
Start: t.StartDate,
End: t.EndDate,
Created: t.Created,
Updated: t.Updated,
DueDate: t.DueDate,
Duration: duration,
RepeatAfter: t.RepeatAfter,
RepeatMode: t.RepeatMode,
Categories: categories,
Priority: t.Priority,
RelatedToParentUID: parentTaskUID,
Start: t.StartDate,
End: t.EndDate,
Created: t.Created,
Updated: t.Updated,
DueDate: t.DueDate,
Duration: duration,
RepeatAfter: t.RepeatAfter,
RepeatMode: t.RepeatMode,
})
}

View File

@ -201,6 +201,120 @@ RRULE:FREQ=SECONDLY;INTERVAL=86400
CATEGORIES:label1,label2
LAST-MODIFIED:20181201T011205Z
END:VTODO
END:VCALENDAR`,
},
{
name: "Format tasks with relationship as Caldav",
args: args{
list: &models.ListWithTasksAndBuckets{
List: models.List{
Title: "List title",
},
},
tasks: []*models.TaskWithComments{
{
Task: models.Task{
Title: "Parent task",
UID: "randomuid_parent",
Description: "This is a parent task",
Priority: 3,
Created: time.Unix(1543626721, 0).In(config.GetTimeZone()),
Updated: time.Unix(1543626725, 0).In(config.GetTimeZone()),
RelatedTasks: map[models.RelationKind][]*models.Task{
models.RelationKindSubtask: {
{
Title: "Subtask 1",
UID: "randomuid_child_1",
Description: "This is the first child task",
Created: time.Unix(1543626724, 0).In(config.GetTimeZone()),
Updated: time.Unix(1543626724, 0).In(config.GetTimeZone()),
},
{
Title: "Subtask 2",
UID: "randomuid_child_2",
Description: "This is the second child task",
Created: time.Unix(1543626724, 0).In(config.GetTimeZone()),
Updated: time.Unix(1543626724, 0).In(config.GetTimeZone()),
},
},
},
},
},
{
Task: models.Task{
Title: "Subtask 1",
UID: "randomuid_child_1",
Description: "This is the first child task",
Created: time.Unix(1543626724, 0).In(config.GetTimeZone()),
Updated: time.Unix(1543626724, 0).In(config.GetTimeZone()),
RelatedTasks: map[models.RelationKind][]*models.Task{
models.RelationKindParenttask: {
{
Title: "Parent task",
UID: "randomuid_parent",
Description: "This is a parent task",
Priority: 3,
Created: time.Unix(1543626721, 0).In(config.GetTimeZone()),
},
},
},
},
},
{
Task: models.Task{
Title: "Subtask 2",
UID: "randomuid_child_2",
Description: "This is the second child task",
Created: time.Unix(1543626724, 0).In(config.GetTimeZone()),
Updated: time.Unix(1543626724, 0).In(config.GetTimeZone()),
RelatedTasks: map[models.RelationKind][]*models.Task{
models.RelationKindParenttask: {
{
Title: "Parent task",
UID: "randomuid_parent",
Description: "This is a parent task",
Priority: 3,
Created: time.Unix(1543626721, 0).In(config.GetTimeZone()),
},
},
},
},
},
},
},
wantCaldav: `BEGIN:VCALENDAR
VERSION:2.0
METHOD:PUBLISH
X-PUBLISHED-TTL:PT4H
X-WR-CALNAME:List title
PRODID:-//Vikunja Todo App//EN
BEGIN:VTODO
UID:randomuid_parent
DTSTAMP:20181201T011205Z
SUMMARY:Parent task
DESCRIPTION:This is a parent task
CREATED:20181201T011201Z
PRIORITY:3
LAST-MODIFIED:20181201T011205Z
END:VTODO
BEGIN:VTODO
UID:randomuid_child_1
DTSTAMP:20181201T011204Z
SUMMARY:Subtask 1
DESCRIPTION:This is the first child task
RELATED-TO;RELTYPE=PARENT:randomuid_parent
CREATED:20181201T011204Z
LAST-MODIFIED:20181201T011204Z
END:VTODO
BEGIN:VTODO
UID:randomuid_child_2
DTSTAMP:20181201T011204Z
SUMMARY:Subtask 2
DESCRIPTION:This is the second child task
RELATED-TO;RELTYPE=PARENT:randomuid_parent
CREATED:20181201T011204Z
LAST-MODIFIED:20181201T011204Z
END:VTODO
END:VCALENDAR`,
},
}