forked from vikunja/vikunja
feat(caldav): add support for repeating tasks
Resolves https://github.com/go-vikunja/api/issues/57#issuecomment-1364373103
This commit is contained in:
parent
ea1d06bda6
commit
c5327845ee
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user