feat(caldav): add support for repeating tasks

Resolves https://github.com/go-vikunja/api/issues/57#issuecomment-1364373103
This commit is contained in:
kolaente 2022-12-24 12:19:51 +01:00
parent ea1d06bda6
commit c5327845ee
Signed by untrusted user: konrad
GPG Key ID: F40E70337AB24C9B
4 changed files with 102 additions and 12 deletions

View File

@ -57,10 +57,12 @@ type Todo struct {
RelatedToUID string RelatedToUID string
Color string Color string
Start time.Time Start time.Time
End time.Time End time.Time
DueDate time.Time DueDate time.Time
Duration time.Duration Duration time.Duration
RepeatAfter int64
RepeatMode string
Created time.Time Created time.Time
Updated time.Time // last-mod Updated time.Time // last-mod
@ -225,6 +227,16 @@ CREATED:` + makeCalDavTimeFromTimeStamp(t.Created)
PRIORITY:` + strconv.Itoa(mapPriorityToCaldav(t.Priority)) PRIORITY:` + strconv.Itoa(mapPriorityToCaldav(t.Priority))
} }
if t.RepeatAfter > 0 || t.RepeatMode == "MONTHLY" {
if t.RepeatMode == "MONTHLY" {
caldavtodos += `
RRULE:FREQ=MONTHLY;BYMONTHDAY=` + t.DueDate.Format("02") // Day of the month
} else {
caldavtodos += `
RRULE:FREQ=SECONDLY;INTERVAL=` + strconv.FormatInt(t.RepeatAfter, 10)
}
}
caldavtodos += ` caldavtodos += `
LAST-MODIFIED:` + makeCalDavTimeFromTimeStamp(t.Updated) LAST-MODIFIED:` + makeCalDavTimeFromTimeStamp(t.Updated)

View File

@ -408,6 +408,77 @@ DESCRIPTION:Lorem Ipsum
PRIORITY:9 PRIORITY:9
LAST-MODIFIED:00010101T000000Z LAST-MODIFIED:00010101T000000Z
END:VTODO END:VTODO
END:VCALENDAR`,
},
{
name: "with repeating monthly",
args: args{
config: &Config{
Name: "test",
ProdID: "RandomProdID which is not random",
},
todos: []*Todo{
{
Summary: "Todo #1",
Description: "Lorem Ipsum",
UID: "randommduid",
Timestamp: time.Unix(1543626724, 0).In(config.GetTimeZone()),
RepeatMode: "MONTHLY",
DueDate: time.Unix(1543626724, 0).In(config.GetTimeZone()),
},
},
},
wantCaldavtasks: `BEGIN:VCALENDAR
VERSION:2.0
METHOD:PUBLISH
X-PUBLISHED-TTL:PT4H
X-WR-CALNAME:test
PRODID:-//RandomProdID which is not random//EN
BEGIN:VTODO
UID:randommduid
DTSTAMP:20181201T011204Z
SUMMARY:Todo #1
DESCRIPTION:Lorem Ipsum
DUE:20181201T011204Z
RRULE:FREQ=MONTHLY;BYMONTHDAY=01
LAST-MODIFIED:00010101T000000Z
END:VTODO
END:VCALENDAR`,
},
{
name: "with repeat mode default",
args: args{
config: &Config{
Name: "test",
ProdID: "RandomProdID which is not random",
},
todos: []*Todo{
{
Summary: "Todo #1",
Description: "Lorem Ipsum",
UID: "randommduid",
Timestamp: time.Unix(1543626724, 0).In(config.GetTimeZone()),
RepeatMode: "DEFAULT",
DueDate: time.Unix(1543626724, 0).In(config.GetTimeZone()),
RepeatAfter: 435,
},
},
},
wantCaldavtasks: `BEGIN:VCALENDAR
VERSION:2.0
METHOD:PUBLISH
X-PUBLISHED-TTL:PT4H
X-WR-CALNAME:test
PRODID:-//RandomProdID which is not random//EN
BEGIN:VTODO
UID:randommduid
DTSTAMP:20181201T011204Z
SUMMARY:Todo #1
DESCRIPTION:Lorem Ipsum
DUE:20181201T011204Z
RRULE:FREQ=SECONDLY;INTERVAL=435
LAST-MODIFIED:00010101T000000Z
END:VTODO
END:VCALENDAR`, END:VCALENDAR`,
}, },
} }

View File

@ -35,6 +35,11 @@ func GetCaldavTodosForTasks(list *models.ListWithTasksAndBuckets, listTasks []*m
duration := t.EndDate.Sub(t.StartDate) duration := t.EndDate.Sub(t.StartDate)
repeatMode := "DEFAULT"
if t.RepeatMode == models.TaskRepeatModeMonth {
repeatMode = "MONTHLY"
}
caldavtodos = append(caldavtodos, &Todo{ caldavtodos = append(caldavtodos, &Todo{
Timestamp: t.Updated, Timestamp: t.Updated,
UID: t.UID, UID: t.UID,
@ -42,13 +47,15 @@ func GetCaldavTodosForTasks(list *models.ListWithTasksAndBuckets, listTasks []*m
Description: t.Description, Description: t.Description,
Completed: t.DoneAt, Completed: t.DoneAt,
// Organizer: &t.CreatedBy, // Disabled until we figure out how this works // Organizer: &t.CreatedBy, // Disabled until we figure out how this works
Priority: t.Priority, Priority: t.Priority,
Start: t.StartDate, Start: t.StartDate,
End: t.EndDate, End: t.EndDate,
Created: t.Created, Created: t.Created,
Updated: t.Updated, Updated: t.Updated,
DueDate: t.DueDate, DueDate: t.DueDate,
Duration: duration, Duration: duration,
RepeatAfter: t.RepeatAfter,
RepeatMode: repeatMode,
}) })
} }

View File

@ -1369,7 +1369,7 @@ func setTaskDatesFromCurrentDateRepeat(oldTask, newTask *Task) {
// This helper function updates the reminders, doneAt, start and end dates of the *old* task // This helper function updates the reminders, doneAt, start and end dates of the *old* task
// and saves the new values in the newTask object. // and saves the new values in the newTask object.
// We make a few assumtions here: // We make a few assumptions here:
// 1. Everything in oldTask is the truth - we figure out if we update anything at all if oldTask.RepeatAfter has a value > 0 // 1. Everything in oldTask is the truth - we figure out if we update anything at all if oldTask.RepeatAfter has a value > 0
// 2. Because of 1., this functions should not be used to update values other than Done in the same go // 2. Because of 1., this functions should not be used to update values other than Done in the same go
func updateDone(oldTask *Task, newTask *Task) { func updateDone(oldTask *Task, newTask *Task) {