Skip to content

Commit

Permalink
fix: do not show deleted recurrences of events
Browse files Browse the repository at this point in the history
Resolves #418, #530
  • Loading branch information
ivan-lednev committed Sep 28, 2024
1 parent 4af69c5 commit 648a446
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 13 deletions.
41 changes: 41 additions & 0 deletions fixtures/google-recurring-with-exception-and-location.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
BEGIN:VCALENDAR
PRODID:-//Google Inc//Google Calendar 70.9054//EN
VERSION:2.0
CALSCALE:GREGORIAN
METHOD:PUBLISH
X-WR-CALNAME:test-ical
X-WR-TIMEZONE:Europe/Warsaw
BEGIN:VTIMEZONE
TZID:Europe/Warsaw
X-LIC-LOCATION:Europe/Warsaw
BEGIN:DAYLIGHT
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
TZNAME:GMT+2
DTSTART:19700329T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
TZNAME:GMT+1
DTSTART:19701025T030000
RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
DTSTART;TZID=Europe/Warsaw:20240927T180000
DTEND;TZID=Europe/Warsaw:20240927T200000
RRULE:FREQ=DAILY
EXDATE;TZID=Europe/Warsaw:20240928T180000
DTSTAMP:20240928T171122Z
UID:[email protected]
CREATED:20240928T170958Z
LAST-MODIFIED:20240928T171047Z
LOCATION:Rynek Główny\, 31-422 Kraków\, Польша
SEQUENCE:1
STATUS:CONFIRMED
SUMMARY:recurring
TRANSP:OPAQUE
END:VEVENT
END:VCALENDAR
2 changes: 1 addition & 1 deletion src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export const editContextKey = "editContext";
export const dateRangeContextKey = "dateRangeContext";
export const errorContextKey = "errorContext";
export const defaultDayFormat = "YYYY-MM-DD";
export const originalRecurrenceDayKeyFormat = "YYYY-MM-DD";
export const icalDayKeyFormat = "YYYY-MM-DD";
export const defaultDayFormatForLuxon = "yyyy-MM-dd";
export const clockSeparator = "--";
export const defaultDurationMinutes = 30;
Expand Down
29 changes: 26 additions & 3 deletions src/remote-calendars.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ function getMockRequest(): Mock {
return jest.requireMock("obsidian").request;
}

function createStore() {
function createStore({ visibleDays = [moment("2024-09-26")] } = {}) {
const syncTrigger = writable({});

const store = useDayToEventOccurences({
isOnline: writable(true),
visibleDays: writable([moment("2024-09-26")]),
visibleDays: writable(visibleDays),
syncTrigger,
settings: writable({
...defaultSettingsForTests,
Expand Down Expand Up @@ -92,7 +92,30 @@ test("Falls back on previous values if fetching a calendar fails", async () => {
});
});

test.todo("Deleted recurrences don't show up as tasks");
test("Deleted recurrences don't show up as tasks", async () => {
getMockRequest().mockReturnValue(
getIcalFixture("google-recurring-with-exception-and-location"),
);

const { store } = createStore({
visibleDays: [moment("2024-09-27"), moment("2024-09-28")],
});

await waitFor(() => {
expect(get(store)).toEqual({
"2024-09-27": {
noTime: [],
withTime: [
expect.objectContaining({
summary: "recurring",
}),
],
},
});
});
});

test.todo("Location gets passed to an event");

test.todo("Yearly recurrences do not show up every month");

Expand Down
28 changes: 19 additions & 9 deletions src/util/ical.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@ import moment, { type Moment } from "moment";
import { tz } from "moment-timezone";
import ical, { type AttendeePartStat } from "node-ical";

import {
fallbackPartStat,
noTitle,
originalRecurrenceDayKeyFormat,
} from "../constants";
import { fallbackPartStat, noTitle, icalDayKeyFormat } from "../constants";
import type { RemoteTask, WithTime } from "../task-types";
import type { WithIcalConfig } from "../types";

Expand All @@ -25,14 +21,24 @@ export function canHappenAfter(icalEvent: ical.VEvent, date: Date) {
);
}

function hasRecurrenceOverride(icalEvent: ical.VEvent, date: Date) {
function hasRecurrenceOverrideForDate(icalEvent: ical.VEvent, date: Date) {
if (!icalEvent.recurrences) {
return false;
}

const dateKey = moment(date).format(originalRecurrenceDayKeyFormat);
return Object.hasOwn(icalEvent.recurrences, getIcalDayKey(date));
}

function getIcalDayKey(date: Date) {
return moment(date).format(icalDayKeyFormat);
}

function hasExceptionForDate(icalEvent: ical.VEvent, date: Date) {
if (!icalEvent.exdate) {
return false;
}

return Object.hasOwn(icalEvent.recurrences, dateKey);
return Object.keys(icalEvent.exdate).includes(getIcalDayKey(date));
}

export function icalEventToTasks(
Expand All @@ -53,7 +59,11 @@ export function icalEventToTasks(

const recurrences = icalEvent.rrule
?.between(startOfDay, endOfDay)
.filter((date) => !hasRecurrenceOverride(icalEvent, date))
.filter(
(date) =>
!hasRecurrenceOverrideForDate(icalEvent, date) &&
!hasExceptionForDate(icalEvent, date),
)
.map((date) => icalEventToTask(icalEvent, date));

return [...recurrences, ...recurrenceOverrides];
Expand Down

0 comments on commit 648a446

Please sign in to comment.