Skip to content

Commit 5f12431

Browse files
feat: show additional rooms in notes when deduplicating calendar events (#210)
* Initial plan * feat: add additional rooms to notes when events are deduplicated When the same lecture has multiple duplicate calendar entries with different room locations (same summary and start time), the deduplication now preserves the additional room information by including them in the event's description/notes field. The format is: Additional rooms: <room1> <room2> <original description> Co-authored-by: kordianbruck <[email protected]> * refactor: prevent duplicate room names in additional rooms list Use a map to track seen locations and prevent duplicates from appearing in the additional rooms section of the description. Co-authored-by: kordianbruck <[email protected]> * Add missing argument. --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: kordianbruck <[email protected]> Co-authored-by: Kordian Bruck <[email protected]> Co-authored-by: Kordian Bruck <[email protected]>
1 parent 44b1ac2 commit 5f12431

File tree

2 files changed

+58
-6
lines changed

2 files changed

+58
-6
lines changed

internal/app.go

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,25 @@ func (a *App) getCleanedCalendar(all []byte, hiddenCourses map[string]bool) (*ic
278278
return nil, err
279279
}
280280

281-
// Create map that tracks if we have already seen a lecture name & datetime (e.g. "lecturexyz-1.2.2024 10:00" -> true)
281+
// First pass: collect all locations for each dedup key (lecture name + datetime)
282+
// This allows us to show additional rooms in the description when events are deduplicated
283+
eventLocations := make(map[string][]string)
284+
for _, component := range cal.Components {
285+
switch component.(type) {
286+
case *ics.VEvent:
287+
event := component.(*ics.VEvent)
288+
eventSummary := event.GetProperty(ics.ComponentPropertySummary).Value
289+
if hiddenCourses[eventSummary] {
290+
continue
291+
}
292+
dedupKey := fmt.Sprintf("%s-%s", eventSummary, event.GetProperty(ics.ComponentPropertyDtStart))
293+
if l := event.GetProperty(ics.ComponentPropertyLocation); l != nil && l.Value != "" {
294+
eventLocations[dedupKey] = append(eventLocations[dedupKey], l.Value)
295+
}
296+
}
297+
}
298+
299+
// Second pass: deduplicate and clean events, adding additional rooms to description
282300
hasLecture := make(map[string]bool)
283301
var newComponents []ics.Component // saves the components we keep because they are not duplicated
284302

@@ -300,8 +318,25 @@ func (a *App) getCleanedCalendar(all []byte, hiddenCourses map[string]bool) (*ic
300318
}
301319
hasLecture[dedupKey] = true // mark event as seen
302320

303-
// clean up the event
304-
a.cleanEvent(event)
321+
// Get additional locations from duplicated events (skip the current event's location and duplicates)
322+
var additionalLocations []string
323+
if locations := eventLocations[dedupKey]; len(locations) > 1 {
324+
currentLocation := ""
325+
if l := event.GetProperty(ics.ComponentPropertyLocation); l != nil {
326+
currentLocation = l.Value
327+
}
328+
seen := make(map[string]bool)
329+
seen[currentLocation] = true
330+
for _, loc := range locations {
331+
if !seen[loc] {
332+
seen[loc] = true
333+
additionalLocations = append(additionalLocations, loc)
334+
}
335+
}
336+
}
337+
338+
// clean up the event (with additional locations for the description)
339+
a.cleanEvent(event, additionalLocations)
305340
newComponents = append(newComponents, event)
306341
default: // keep everything that is not an event (metadata etc.)
307342
newComponents = append(newComponents, component)
@@ -342,7 +377,7 @@ var reRoom = regexp.MustCompile("^(.*?),.*?(\\d{4})\\.(?:\\d\\d|EG|UG|DG|Z\\d|U\
342377
// matches strings like: (5612.03.017), (5612.EG.017), (5612.EG.010B)
343378
var reNavigaTUM = regexp.MustCompile("\\(\\d{4}\\.[a-zA-Z0-9]{2}\\.\\d{3}[A-Z]?\\)")
344379

345-
func (a *App) cleanEvent(event *ics.VEvent) {
380+
func (a *App) cleanEvent(event *ics.VEvent, additionalLocations []string) {
346381
summary := ""
347382
if s := event.GetProperty(ics.ComponentPropertySummary); s != nil {
348383
summary = cleanEventSummary(s.Value)
@@ -388,6 +423,12 @@ func (a *App) cleanEvent(event *ics.VEvent) {
388423
}
389424
}
390425
}
426+
427+
// Add additional locations from deduplicated events to the description
428+
if len(additionalLocations) > 0 {
429+
description = "Additional rooms:\n" + strings.Join(additionalLocations, "\n") + "\n\n" + description
430+
}
431+
391432
event.SetDescription(description)
392433

393434
// set title on summary:

internal/app_test.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,17 @@ func TestDeduplication(t *testing.T) {
6969
t.Errorf("Calendar should have only 1 entry after deduplication but has %d", len(calendar.Components))
7070
return
7171
}
72+
73+
// Verify that the additional room from the deduplicated event is in the description
74+
desc := calendar.Components[0].(*ics.VEvent).GetProperty(ics.ComponentPropertyDescription).Value
75+
if !strings.Contains(desc, "Additional rooms:") {
76+
t.Error("Description should contain 'Additional rooms:' when events are deduplicated with different locations")
77+
return
78+
}
79+
if !strings.Contains(desc, "MI HS 1") {
80+
t.Error("Description should contain the additional room 'MI HS 1' from the deduplicated event")
81+
return
82+
}
7283
}
7384

7485
func TestMultipleRooms(t *testing.T) {
@@ -94,7 +105,7 @@ func TestMultipleRooms(t *testing.T) {
94105
event.SetProperty(ics.ComponentPropertyDescription, "Original Description")
95106
event.SetProperty(ics.ComponentPropertyStatus, "CONFIRMED")
96107

97-
app.cleanEvent(event)
108+
app.cleanEvent(event, []string{})
98109

99110
desc := event.GetProperty(ics.ComponentPropertyDescription).Value
100111
loc := event.GetProperty(ics.ComponentPropertyLocation).Value
@@ -153,7 +164,7 @@ func TestLocationReplacement(t *testing.T) {
153164
return
154165
}
155166
desc := calendar.Components[0].(*ics.VEvent).GetProperty(ics.ComponentPropertyDescription).Value
156-
expectedDescription := "https://nav.tum.de/room/5508.02.801\nMW 1801, Ernst-Schmidt-Hörsaal (5508.02.801)\nEinführung in die Rechnerarchitektur\nfix; Abhaltung;"
167+
expectedDescription := "Additional rooms:\nMI HS 1\n\nhttps://nav.tum.de/room/5508.02.801\nMW 1801, Ernst-Schmidt-Hörsaal (5508.02.801)\nEinführung in die Rechnerarchitektur\nfix; Abhaltung;"
157168
if desc != expectedDescription {
158169
t.Errorf("Description should be %s but is %s", expectedDescription, desc)
159170
return

0 commit comments

Comments
 (0)