From 334f7d101a4816001dbd8e15142d7a0126735c2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Mon, 18 Nov 2024 18:09:45 +0100 Subject: [PATCH 1/2] WIP: handle cancelled ical events Doesn't compile yet, no time to continue for now. Fix: #2 --- animmeetings.go | 41 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/animmeetings.go b/animmeetings.go index 28010eb..4c23849 100644 --- a/animmeetings.go +++ b/animmeetings.go @@ -129,7 +129,22 @@ func (cal *RemoteCalendar) LoadNextMeetingTime(ctx context.Context) (time.Time, var nextStartTime time.Time for eventIndex, event := range events { + uid := event.GetProperty(ical.ComponentPropertyUniqueId) + if uid == nil { + log.Warn("calendar: ignoring entry without UID property") + continue + } + + // Skip cancelled meetings. + if isCancelled(event) { + continue + } + dtStart := event.GetProperty(ical.ComponentPropertyDtStart) + if dtStart == nil { + log.Warn("calendar: ignoring entry without DTSTART property", "uid", uid.Value) + continue + } parsedDtStart, err := time.Parse(icalTimeFormat, dtStart.Value) if err != nil { log.Warn("calendar: could not parse DTSTART property", "value", dtStart.Value, "cause", err) @@ -146,17 +161,22 @@ func (cal *RemoteCalendar) LoadNextMeetingTime(ctx context.Context) (time.Time, return nextStartTime, nil } -func (cal *RemoteCalendar) MeetingsOnMonth(ctx context.Context, timeInMonth time.Time) []time.Time { +type MeetingInfo struct { + StartTime time.Time + IsCancelled bool +} + +func (cal *RemoteCalendar) MeetingsOnMonth(ctx context.Context, timeInMonth time.Time) []MeetingInfo { log := GetBotLog(ctx) calendar, err := cal.LoadFromDisk(ctx) if err != nil { log.Warn("could not load calendar from disk, pretending there are no meetings", "cause", err) - return []time.Time{} + return []MeetingInfo{} } events := calendar.Events() - inMonth := []time.Time{} + inMonth := []MeetingInfo{} year := timeInMonth.Year() month := timeInMonth.Month() @@ -173,7 +193,12 @@ func (cal *RemoteCalendar) MeetingsOnMonth(ctx context.Context, timeInMonth time if parsedDtStart.Year() != year || parsedDtStart.Month() != month { continue } - inMonth = append(inMonth, parsedDtStart.In(location)) + + meetingInfo := MeetingInfo{ + StartTime: parsedDtStart.In(location), + IsCancelled: isCancelled(event), + } + inMonth = append(inMonth, meetingInfo) } return inMonth @@ -294,3 +319,11 @@ func fileExists(path string) bool { return true } } + +func isCancelled(event *ical.VEvent) bool { + status := event.GetProperty(ical.ComponentPropertyStatus) + if status == nil { + return false + } + return status.Value == string(ical.ObjectStatusCancelled) +} -- 2.30.2 From fc9aa2be30f03879285463835bbe528bfed611c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Tue, 19 Nov 2024 15:18:45 +0100 Subject: [PATCH 2/2] It compiles --- call_and_response.go | 4 +++- call_and_response_cmd_cal.go | 16 ++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/call_and_response.go b/call_and_response.go index 2771896..337fb56 100644 --- a/call_and_response.go +++ b/call_and_response.go @@ -23,9 +23,11 @@ var _ EventConsumer = (*CallAndReponse)(nil) // MeetingTimer provides the next meeting time. type MeetingTimer interface { NextMeetingTime() time.Time - MeetingsOnMonth(ctx context.Context, timeInMonth time.Time) []time.Time + MeetingsOnMonth(ctx context.Context, timeInMonth time.Time) []MeetingInfo } +var _ MeetingTimer = (*RemoteCalendar)(nil) + type CallAndResponseCommand interface { CmdTag() string CmdDescription() string diff --git a/call_and_response_cmd_cal.go b/call_and_response_cmd_cal.go index 6001c96..d5b7391 100644 --- a/call_and_response_cmd_cal.go +++ b/call_and_response_cmd_cal.go @@ -51,10 +51,10 @@ func (c *CmdCalendar) Handle(ctx context.Context, car *CallAndReponse, evt *even car.sendReplyInThread(ctx, evt, calendarMD) } -func MeetingCalendar(ctx context.Context, meetingTimes []time.Time) string { +func MeetingCalendar(ctx context.Context, meetings []MeetingInfo) string { log := GetBotLog(ctx) - dateInMonth := meetingTimes[0] + dateInMonth := meetings[0].StartTime firstOfMonth := time.Date(dateInMonth.Year(), dateInMonth.Month(), 1, 0, 0, 0, 0, dateInMonth.Location()) lastOfMonth := firstOfMonth.AddDate(0, 1, -1) @@ -70,10 +70,14 @@ func MeetingCalendar(ctx context.Context, meetingTimes []time.Time) string { meetingCal[weekIndex][weekdayIndex] = fmt.Sprintf("%2d", dayNum) } - for _, meetingTime := range meetingTimes { - weekIndex, weekdayIndex := calendarIndex(meetingTime, firstOfMonth) - // dayNum := strings.TrimSpace(meetingCal[weekIndex][weekdayIndex]) - entry := "" + meetingTime.Format("15:04") + "" + for _, meeting := range meetings { + weekIndex, weekdayIndex := calendarIndex(meeting.StartTime, firstOfMonth) + var entry string + if meeting.IsCancelled { + entry = "❌" + } else { + entry = "" + meeting.StartTime.Format("15:04") + "" + } meetingCal[weekIndex][weekdayIndex] = entry } -- 2.30.2