fix: match reminder paring with caldav spec and tasks.org code
All checks were successful
continuous-integration/drone/pr Build is passing

Follow the RFC more strictly:
https://icalendar.org/iCalendar-RFC-5545/3-8-6-3-trigger.html

Compare with tasks.org, to make sure their alarms will be correctly synced:
https://github.com/tasks/tasks/blob/main/app/src/main/java/org/tasks/caldav/extensions/VAlarm.kt
This commit is contained in:
cernst 2023-03-29 23:36:44 +02:00
parent 3e49c27ad1
commit 287a21da93
4 changed files with 48 additions and 40 deletions

View File

@ -204,13 +204,10 @@ func ParseAlarms(alarms []Alarm, taskDescription string) (caldavalarms string) {
caldavalarms += ` caldavalarms += `
BEGIN:VALARM` BEGIN:VALARM`
switch a.RelativeTo { switch a.RelativeTo {
case models.ReminderRelationDueDate:
caldavalarms += `
TRIGGER:` + makeCalDavDuration(a.Duration)
case models.ReminderRelationStartDate: case models.ReminderRelationStartDate:
caldavalarms += ` caldavalarms += `
TRIGGER;RELATED=START:` + makeCalDavDuration(a.Duration) TRIGGER;RELATED=START:` + makeCalDavDuration(a.Duration)
case models.ReminderRelationEndDate: case models.ReminderRelationEndDate, models.ReminderRelationDueDate:
caldavalarms += ` caldavalarms += `
TRIGGER;RELATED=END:` + makeCalDavDuration(a.Duration) TRIGGER;RELATED=END:` + makeCalDavDuration(a.Duration)
default: default:

View File

@ -311,7 +311,7 @@ ACTION:DISPLAY
DESCRIPTION:alarm description DESCRIPTION:alarm description
END:VALARM END:VALARM
BEGIN:VALARM BEGIN:VALARM
TRIGGER:-PT2H0M0S TRIGGER;RELATED=END:-PT2H0M0S
ACTION:DISPLAY ACTION:DISPLAY
DESCRIPTION:Todo #1 DESCRIPTION:Todo #1
END:VALARM END:VALARM

View File

@ -141,53 +141,56 @@ func ParseTaskFromVTODO(content string) (vTask *models.Task, err error) {
vTask.EndDate = vTask.StartDate.Add(duration) vTask.EndDate = vTask.StartDate.Add(duration)
} }
reminders := make([]*models.TaskReminder, 0)
for _, vAlarm := range vTodo.SubComponents() { for _, vAlarm := range vTodo.SubComponents() {
if vAlarm, ok := vAlarm.(*ics.VAlarm); ok { if vAlarm, ok := vAlarm.(*ics.VAlarm); ok {
reminders = parseVAlarm(vAlarm, reminders) vTask = parseVAlarm(vAlarm, vTask)
} }
} }
if len(reminders) > 0 {
vTask.Reminders = reminders
}
return return
} }
func parseVAlarm(vAlarm *ics.VAlarm, reminders []*models.TaskReminder) []*models.TaskReminder { func parseVAlarm(vAlarm *ics.VAlarm, vTask *models.Task) *models.Task {
for _, property := range vAlarm.UnknownPropertiesIANAProperties() { for _, property := range vAlarm.UnknownPropertiesIANAProperties() {
if property.IANAToken == "TRIGGER" { if property.IANAToken == "TRIGGER" {
switch { if contains(property.ICalParameters["VALUE"], "DATE-TIME") {
case len(property.ICalParameters["VALUE"]) > 0: // Example: TRIGGER;VALUE=DATE-TIME:20181201T011210Z
if property.ICalParameters["VALUE"][0] == "DATE-TIME" { vTask.Reminders = append(vTask.Reminders, &models.TaskReminder{
// Example: TRIGGER;VALUE=DATE-TIME:20181201T011210Z Reminder: caldavTimeToTimestamp(property.Value)})
reminders = append(reminders, &models.TaskReminder{ } else {
Reminder: caldavTimeToTimestamp(property.Value)}) if contains(property.ICalParameters["RELATED"], "END") {
} // Example: TRIGGER;RELATED=END:-P2D
case len(property.ICalParameters["RELATED"]) > 0: duration := utils.ParseISO8601Duration(property.Value)
duration := utils.ParseISO8601Duration(property.Value) if vTask.EndDate.IsZero() {
switch property.ICalParameters["RELATED"][0] { vTask.Reminders = append(vTask.Reminders, &models.TaskReminder{
case "START": RelativePeriod: int64(duration.Seconds()),
RelativeTo: models.ReminderRelationDueDate})
} else {
vTask.Reminders = append(vTask.Reminders, &models.TaskReminder{
RelativePeriod: int64(duration.Seconds()),
RelativeTo: models.ReminderRelationEndDate})
}
} else {
// Example: TRIGGER;RELATED=START:-P2D // Example: TRIGGER;RELATED=START:-P2D
reminders = append(reminders, &models.TaskReminder{ // Example: TRIGGER:-PT60M
duration := utils.ParseISO8601Duration(property.Value)
vTask.Reminders = append(vTask.Reminders, &models.TaskReminder{
RelativePeriod: int64(duration.Seconds()), RelativePeriod: int64(duration.Seconds()),
RelativeTo: models.ReminderRelationStartDate}) RelativeTo: models.ReminderRelationStartDate})
case "END":
// Example: TRIGGER;RELATED=END:-P2D
reminders = append(reminders, &models.TaskReminder{
RelativePeriod: int64(duration.Seconds()),
RelativeTo: models.ReminderRelationEndDate})
} }
default:
duration := utils.ParseISO8601Duration(property.Value)
// Example: TRIGGER:-PT60M
reminders = append(reminders, &models.TaskReminder{
RelativePeriod: int64(duration.Seconds()),
RelativeTo: models.ReminderRelationDueDate})
} }
} }
} }
return reminders return vTask
}
func contains(array []string, str string) bool {
for _, value := range array {
if value == str {
return true
}
}
return false
} }
// https://tools.ietf.org/html/rfc5545#section-3.3.5 // https://tools.ietf.org/html/rfc5545#section-3.3.5

View File

@ -170,7 +170,11 @@ TRIGGER:PT0S
ACTION:DISPLAY ACTION:DISPLAY
END:VALARM END:VALARM
BEGIN:VALARM BEGIN:VALARM
TRIGGER:-PT60M TRIGGER;VALUE=DURATION:-PT60M
ACTION:DISPLAY
END:VALARM
BEGIN:VALARM
TRIGGER:-PT61M
ACTION:DISPLAY ACTION:DISPLAY
END:VALARM END:VALARM
BEGIN:VALARM BEGIN:VALARM
@ -192,19 +196,23 @@ END:VCALENDAR`,
DueDate: time.Date(2023, 3, 4, 15, 0, 0, 0, config.GetTimeZone()), DueDate: time.Date(2023, 3, 4, 15, 0, 0, 0, config.GetTimeZone()),
Reminders: []*models.TaskReminder{ Reminders: []*models.TaskReminder{
{ {
RelativeTo: models.ReminderRelationDueDate, RelativeTo: models.ReminderRelationStartDate,
RelativePeriod: 0, RelativePeriod: 0,
}, },
{ {
RelativeTo: models.ReminderRelationDueDate, RelativeTo: models.ReminderRelationStartDate,
RelativePeriod: -3600, RelativePeriod: -3600,
}, },
{
RelativeTo: models.ReminderRelationStartDate,
RelativePeriod: -3660,
},
{ {
RelativeTo: models.ReminderRelationStartDate, RelativeTo: models.ReminderRelationStartDate,
RelativePeriod: -86400, RelativePeriod: -86400,
}, },
{ {
RelativeTo: models.ReminderRelationEndDate, RelativeTo: models.ReminderRelationDueDate,
RelativePeriod: -1800, RelativePeriod: -1800,
}, },
}, },
@ -309,7 +317,7 @@ ACTION:DISPLAY
DESCRIPTION:Task 1 DESCRIPTION:Task 1
END:VALARM END:VALARM
BEGIN:VALARM BEGIN:VALARM
TRIGGER:-PT1H0M0S TRIGGER;RELATED=END:-PT1H0M0S
ACTION:DISPLAY ACTION:DISPLAY
DESCRIPTION:Task 1 DESCRIPTION:Task 1
END:VALARM END:VALARM