feat: convert Reminders to VALARMs
continuous-integration/drone/pr Build is failing Details

This commit is contained in:
cernst 2023-03-16 17:10:21 +01:00
parent 30c1d698e9
commit 06508f0287
4 changed files with 153 additions and 93 deletions

View File

@ -61,6 +61,8 @@ type Todo struct {
// Alarm holds infos about an alarm from a caldav event
type Alarm struct {
Time time.Time
Duration time.Duration
RelativeTo string
Description string
}
@ -182,19 +184,7 @@ CATEGORIES:` + strings.Join(t.Categories, ",")
caldavtodos += `
LAST-MODIFIED:` + makeCalDavTimeFromTimeStamp(t.Updated)
for _, a := range t.Alarms {
if a.Description == "" {
a.Description = t.Summary
}
caldavtodos += `
BEGIN:VALARM
TRIGGER;VALUE=DATE-TIME:` + makeCalDavTimeFromTimeStamp(a.Time) + `
ACTION:DISPLAY
DESCRIPTION:` + a.Description + `
END:VALARM`
}
caldavtodos += ParseAlarms(t.Alarms, t.Summary)
caldavtodos += `
END:VTODO`
}
@ -205,10 +195,49 @@ END:VCALENDAR` // Need a line break
return
}
func ParseAlarms(alarms []Alarm, taskDescription string) (caldavalarms string) {
for _, a := range alarms {
if a.Description == "" {
a.Description = taskDescription
}
caldavalarms += `
BEGIN:VALARM`
switch a.RelativeTo {
case "due_date":
caldavalarms += `
TRIGGER:` + makeCalDavDuration(a.Duration)
case "start_date":
caldavalarms += `
TRIGGER;RELATED=START:` + makeCalDavDuration(a.Duration)
case "end_date":
caldavalarms += `
TRIGGER;RELATED=END:` + makeCalDavDuration(a.Duration)
default:
caldavalarms += `
TRIGGER;VALUE=DATE-TIME:` + makeCalDavTimeFromTimeStamp(a.Time)
}
caldavalarms += `
ACTION:DISPLAY
DESCRIPTION:` + a.Description + `
END:VALARM`
}
return caldavalarms
}
func makeCalDavTimeFromTimeStamp(ts time.Time) (caldavtime string) {
return ts.In(time.UTC).Format(DateFormat) + "Z"
}
func makeCalDavDuration(duration time.Duration) (caldavtime string) {
if duration < 0 {
duration = duration.Abs()
caldavtime = "-"
}
caldavtime += "PT" + strings.ToUpper(duration.Truncate(time.Millisecond).String())
return
}
func calcAlarmDateFromReminder(eventStart, reminder time.Time) (alarmTime string) {
diff := reminder.Sub(eventStart)
diffStr := strings.ToUpper(diff.String())

View File

@ -273,6 +273,18 @@ END:VCALENDAR`,
Time: time.Unix(1543626724, 0).In(config.GetTimeZone()),
Description: "alarm description",
},
{
Duration: -2 * time.Hour,
RelativeTo: "due_date",
},
{
Duration: 1 * time.Hour,
RelativeTo: "start_date",
},
{
Duration: time.Duration(0),
RelativeTo: "end_date",
},
},
},
},
@ -298,6 +310,21 @@ TRIGGER;VALUE=DATE-TIME:20181201T011204Z
ACTION:DISPLAY
DESCRIPTION:alarm description
END:VALARM
BEGIN:VALARM
TRIGGER:-PT2H0M0S
ACTION:DISPLAY
DESCRIPTION:Todo #1
END:VALARM
BEGIN:VALARM
TRIGGER;RELATED=START:PT1H0M0S
ACTION:DISPLAY
DESCRIPTION:Todo #1
END:VALARM
BEGIN:VALARM
TRIGGER;RELATED=END:PT0S
ACTION:DISPLAY
DESCRIPTION:Todo #1
END:VALARM
END:VTODO
END:VCALENDAR`,
},
@ -305,7 +332,7 @@ END:VCALENDAR`,
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotCaldavtasks := ParseTodos(tt.args.config, tt.args.todos)
assert.Equal(t, gotCaldavtasks, tt.wantCaldavtasks)
assert.Equal(t, tt.wantCaldavtasks, gotCaldavtasks)
})
}
}

View File

@ -43,7 +43,9 @@ func GetCaldavTodosForTasks(project *models.ProjectWithTasksAndBuckets, projectT
var alarms []Alarm
for _, reminder := range t.Reminders {
alarms = append(alarms, Alarm{
Time: reminder,
Time: reminder.Reminder,
Duration: time.Duration(reminder.RelativePeriod) * time.Second,
RelativeTo: string(reminder.RelativeTo),
})
}
@ -156,36 +158,32 @@ func parseVAlarm(vAlarm *ics.VAlarm, vTask *models.Task) {
switch property.ICalParameters["VALUE"][0] {
case "DATE-TIME":
// Example: TRIGGER;VALUE=DATE-TIME:20181201T011210Z
vTask.Reminders = append(vTask.Reminders, caldavTimeToTimestamp(property.Value))
vTask.ReminderDates = append(vTask.ReminderDates, caldavTimeToTimestamp(property.Value))
}
// At the moment I don't think this should be merged. Relative triggers cannot
// be stored properly. This would result in missing or duplicate alarms on the
// client.
//
// } else if len(property.ICalParameters["RELATED"]) > 0 {
// duration := parseDuration(property.Value)
// switch property.ICalParameters["RELATED"][0] {
// case "START":
// // Example: TRIGGER;RELATED=START:-P2D
// if !vTask.StartDate.IsZero() {
// vTask.Reminders = append(vTask.Reminders, vTask.StartDate.Add(duration))
// }
// case "END":
// // Example: TRIGGER;RELATED=END:-P2D
// if !vTask.EndDate.IsZero() {
// vTask.Reminders = append(vTask.Reminders, vTask.EndDate.Add(duration))
// } else if !vTask.DueDate.IsZero() {
// vTask.Reminders = append(vTask.Reminders, vTask.DueDate.Add(duration))
// }
// }
// } else {
// duration := parseDuration(property.Value)
// if duration != 0 {
// // Example: TRIGGER:-PT60M
// if !vTask.DueDate.IsZero() {
// vTask.Reminders = append(vTask.Reminders, vTask.DueDate.Add(duration))
// }
// }
//} else if len(property.ICalParameters["RELATED"]) > 0 {
// duration := parseDuration(property.Value)
// switch property.ICalParameters["RELATED"][0] {
// case "START":
// // Example: TRIGGER;RELATED=START:-P2D
// if !vTask.StartDate.IsZero() {
// vTask.Reminders = append(vTask.Reminders, vTask.StartDate.Add(duration))
// }
// case "END":
// // Example: TRIGGER;RELATED=END:-P2D
// if !vTask.EndDate.IsZero() {
// vTask.Reminders = append(vTask.Reminders, vTask.EndDate.Add(duration))
// } else if !vTask.DueDate.IsZero() {
// vTask.Reminders = append(vTask.Reminders, vTask.DueDate.Add(duration))
// }
// }
//} else {
// duration := parseDuration(property.Value)
// if duration != 0 {
// // Example: TRIGGER:-PT60M
// if !vTask.DueDate.IsZero() {
// vTask.Reminders = append(vTask.Reminders, vTask.DueDate.Add(duration))
// }
// }
}
}
}

View File

@ -142,56 +142,56 @@ END:VCALENDAR`,
Title: "Todo #1",
UID: "randomuid",
Description: "Lorem Ipsum",
Reminders: []time.Time{
ReminderDates: []time.Time{
time.Date(2018, 12, 1, 1, 12, 10, 0, config.GetTimeZone()),
},
Updated: time.Unix(1543626724, 0).In(config.GetTimeZone()),
},
},
// {
// name: "With alarm (relative trigger)",
// args: args{content: `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:randomuid
// DTSTAMP:20181201T011204
// SUMMARY:Todo #1
// DESCRIPTION:Lorem Ipsum
// DTSTART:20230228T170000Z
// DUE:20230304T150000Z
// BEGIN:VALARM
// TRIGGER:-PT60M
// ACTION:DISPLAY
// END:VALARM
// BEGIN:VALARM
// TRIGGER;RELATED=START:-P1D
// ACTION:DISPLAY
// END:VALARM
// BEGIN:VALARM
// TRIGGER;RELATED=END:-PT30M
// ACTION:DISPLAY
// END:VALARM
// END:VTODO
// END:VCALENDAR`,
// },
// wantVTask: &models.Task{
// Title: "Todo #1",
// UID: "randomuid",
// Description: "Lorem Ipsum",
// StartDate: time.Date(2023, 2, 28, 17, 0, 0, 0, config.GetTimeZone()),
// DueDate: time.Date(2023, 3, 4, 15, 0, 0, 0, config.GetTimeZone()),
// Reminders: []time.Time{
// time.Date(2023, 3, 4, 14, 0, 0, 0, config.GetTimeZone()),
// time.Date(2023, 2, 27, 17, 00, 0, 0, config.GetTimeZone()),
// time.Date(2023, 3, 4, 14, 30, 0, 0, config.GetTimeZone()),
// },
// Updated: time.Unix(1543626724, 0).In(config.GetTimeZone()),
// },
// },
// {
// name: "With alarm (relative trigger)",
// args: args{content: `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:randomuid
// DTSTAMP:20181201T011204
// SUMMARY:Todo #1
// DESCRIPTION:Lorem Ipsum
// DTSTART:20230228T170000Z
// DUE:20230304T150000Z
// BEGIN:VALARM
// TRIGGER:-PT60M
// ACTION:DISPLAY
// END:VALARM
// BEGIN:VALARM
// TRIGGER;RELATED=START:-P1D
// ACTION:DISPLAY
// END:VALARM
// BEGIN:VALARM
// TRIGGER;RELATED=END:-PT30M
// ACTION:DISPLAY
// END:VALARM
// END:VTODO
// END:VCALENDAR`,
// },
// wantVTask: &models.Task{
// Title: "Todo #1",
// UID: "randomuid",
// Description: "Lorem Ipsum",
// StartDate: time.Date(2023, 2, 28, 17, 0, 0, 0, config.GetTimeZone()),
// DueDate: time.Date(2023, 3, 4, 15, 0, 0, 0, config.GetTimeZone()),
// Reminders: []time.Time{
// time.Date(2023, 3, 4, 14, 0, 0, 0, config.GetTimeZone()),
// time.Date(2023, 2, 27, 17, 00, 0, 0, config.GetTimeZone()),
// time.Date(2023, 3, 4, 14, 30, 0, 0, config.GetTimeZone()),
// },
// Updated: time.Unix(1543626724, 0).In(config.GetTimeZone()),
// },
// },
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
@ -249,9 +249,15 @@ func TestGetCaldavTodosForTasks(t *testing.T) {
Title: "label2",
},
},
Reminders: []time.Time{
time.Unix(1543626730, 0).In(config.GetTimeZone()),
time.Unix(1543626731, 0).In(config.GetTimeZone()),
Reminders: []*models.TaskReminder{
{
Reminder: time.Unix(1543626730, 0).In(config.GetTimeZone()),
},
{
Reminder: time.Unix(1543626731, 0).In(config.GetTimeZone()),
RelativePeriod: -3600,
RelativeTo: models.ReminderRelationDueDate,
},
},
},
},
@ -284,7 +290,7 @@ ACTION:DISPLAY
DESCRIPTION:Task 1
END:VALARM
BEGIN:VALARM
TRIGGER;VALUE=DATE-TIME:20181201T011211Z
TRIGGER:-PT1H0M0S
ACTION:DISPLAY
DESCRIPTION:Task 1
END:VALARM