Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[icalendar] Fix internal calculation for retrieving events for command tags #11178

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 2 additions & 8 deletions bundles/org.openhab.binding.icalendar/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@
<dependency>
<groupId>net.sf.biweekly</groupId>
<artifactId>biweekly</artifactId>
<version>0.6.4</version>
<version>0.6.6</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>*</artifactId>
<artifactId>jackson-databind</artifactId>
</exclusion>
</exclusions>
</dependency>
Expand All @@ -39,12 +39,6 @@
<version>${jackson.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,55 +88,14 @@ class BiweeklyPresentableCalendar extends AbstractPresentableCalendar {

@Override
public List<Event> getJustBegunEvents(Instant frameBegin, Instant frameEnd) {
final List<Event> eventList = new ArrayList<>();
// process all the events in the iCalendar
for (final VEvent event : usedCalendar.getEvents()) {
// iterate over all begin dates
final DateIterator begDates = getRecurredEventDateIterator(event);
while (begDates.hasNext()) {
final Instant begInst = begDates.next().toInstant();
if (begInst.isBefore(frameBegin)) {
continue;
} else if (begInst.isAfter(frameEnd)) {
break;
}
// fall through => means we are within the time frame
Duration duration = getEventLength(event);
if (duration == null) {
duration = Duration.ofMinutes(1);
}
eventList.add(new VEventWPeriod(event, begInst, begInst.plus(duration)).toEvent());
break;
}
}
return eventList;
return this.getVEventWPeriodsBetween(frameBegin, frameEnd, 0).stream().map(e -> e.toEvent())
.collect(Collectors.toList());
}

@Override
public List<Event> getJustEndedEvents(Instant frameBegin, Instant frameEnd) {
final List<Event> eventList = new ArrayList<>();
// process all the events in the iCalendar
for (final VEvent event : usedCalendar.getEvents()) {
final Duration duration = getEventLength(event);
if (duration == null) {
continue;
}
// iterate over all begin dates
final DateIterator begDates = getRecurredEventDateIterator(event);
while (begDates.hasNext()) {
final Instant begInst = begDates.next().toInstant();
final Instant endInst = begInst.plus(duration);
if (endInst.isBefore(frameBegin)) {
continue;
} else if (endInst.isAfter(frameEnd)) {
break;
}
// fall through => means we are within the time frame
eventList.add(new VEventWPeriod(event, begInst, endInst).toEvent());
break;
}
}
return eventList;
return this.getVEventWPeriodsBetween(frameBegin, frameEnd, 0, true).stream().map(e -> e.toEvent())
.collect(Collectors.toList());
}

@Override
Expand Down Expand Up @@ -247,23 +206,43 @@ public List<Event> getFilteredEventsBetween(Instant begin, Instant end, @Nullabl
* @return All events which begin in the time frame.
*/
private List<VEventWPeriod> getVEventWPeriodsBetween(Instant frameBegin, Instant frameEnd, int maximumPerSeries) {
return this.getVEventWPeriodsBetween(frameBegin, frameEnd, maximumPerSeries, false);
}

/**
* Finds events which begin in the given frame by end time and date
*
* @param frameBegin Begin of the frame where to search events.
* @param frameEnd End of the time frame where to search events. The Instant is inclusive when searchByEnd is true.
* @param maximumPerSeries Limit the results per series. Set to 0 for no limit.
* @param searchByEnd Whether to search by begin of the event or by end.
* @return All events which begin in the time frame.
*/
private List<VEventWPeriod> getVEventWPeriodsBetween(Instant frameBegin, Instant frameEnd, int maximumPerSeries,
boolean searchByEnd) {
final List<VEvent> positiveEvents = new ArrayList<>();
final List<VEvent> negativeEvents = new ArrayList<>();
classifyEvents(positiveEvents, negativeEvents);

final List<VEventWPeriod> eventList = new ArrayList<>();
for (final VEvent positiveEvent : positiveEvents) {
final DateIterator positiveBeginDates = getRecurredEventDateIterator(positiveEvent);
positiveBeginDates.advanceTo(Date.from(frameBegin));
Duration duration = getEventLength(positiveEvent);
if (duration == null) {
duration = Duration.ZERO;
}
positiveBeginDates.advanceTo(Date.from(frameBegin.minus(searchByEnd ? duration : Duration.ZERO)));
int foundInSeries = 0;
while (positiveBeginDates.hasNext()) {
final Instant begInst = positiveBeginDates.next().toInstant();
if (begInst.isAfter(frameEnd) || begInst.equals(frameEnd)) {
if ((!searchByEnd && (begInst.isAfter(frameEnd) || begInst.equals(frameEnd)))
|| (searchByEnd && begInst.plus(duration).isAfter(frameEnd))) {
break;
}
Duration duration = getEventLength(positiveEvent);
if (duration == null) {
duration = Duration.ZERO;
// biweekly is not as precise as java.time. An exact check is required.
if ((!searchByEnd && begInst.isBefore(frameBegin))
|| (searchByEnd && begInst.plus(duration).isBefore(frameBegin))) {
continue;
}

final VEventWPeriod resultingVEWP = new VEventWPeriod(positiveEvent, begInst, begInst.plus(duration));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public class BiweeklyPresentableCalendarTest {
private AbstractPresentableCalendar calendar3;
private AbstractPresentableCalendar calendar_issue9647;
private AbstractPresentableCalendar calendar_issue10808;
private AbstractPresentableCalendar calendar_issue11084;

@BeforeEach
public void setUp() throws IOException, CalendarException {
Expand All @@ -59,6 +60,8 @@ public void setUp() throws IOException, CalendarException {
new FileInputStream("src/test/resources/test-issue9647.ics"));
calendar_issue10808 = new BiweeklyPresentableCalendar(
new FileInputStream("src/test/resources/test-issue10808.ics"));
calendar_issue11084 = new BiweeklyPresentableCalendar(
new FileInputStream("src/test/resources/test-issue11084.ics"));
}

/**
Expand Down Expand Up @@ -132,6 +135,13 @@ public void testGetCurrentEvent() {
Event currentEvent4 = calendar_issue10808.getCurrentEvent(Instant.parse("2021-06-05T17:18:05Z"));
assertNotNull(currentEvent4);
assertTrue("Test event 1".contentEquals(currentEvent4.title));

Event currentEvent5 = calendar_issue11084.getCurrentEvent(Instant.parse("2021-08-16T16:30:05Z"));
assertNull(currentEvent5);

Event currentEvent6 = calendar_issue11084.getCurrentEvent(Instant.parse("2021-08-16T16:45:05Z"));
assertNotNull(currentEvent6);
assertTrue("TEST_REPEATING_EVENT_3".contentEquals(currentEvent6.title));
}

/**
Expand Down Expand Up @@ -563,6 +573,17 @@ public void testCommandTagCode() {
cmd7 = cmdTags.get(7).getCommand();
assertNotNull(cmd7);
assertEquals(DecimalType.class, cmd7.getClass());

// issue 11084: Command tags from moved events are also executed
List<Event> events2 = calendar_issue11084.getJustBegunEvents(Instant.parse("2021-08-16T16:29:55Z"),
Instant.parse("2021-08-16T17:00:05Z"));
assertEquals(1, events2.size());
assertEquals(Instant.parse("2021-08-16T16:45:00Z"), events2.get(0).start);

List<Event> events3 = calendar_issue11084.getJustEndedEvents(Instant.parse("2021-08-16T16:29:55Z"),
Instant.parse("2021-08-16T17:00:05Z"));
assertEquals(1, events3.size());
assertEquals(Instant.parse("2021-08-16T17:00:00Z"), events3.get(0).end);
}

@SuppressWarnings("null")
Expand Down Expand Up @@ -621,5 +642,9 @@ public void testGetFilteredEventsBetween() {
LocalDate.parse("2021-01-04").atStartOfDay(ZoneId.systemDefault()).toInstant(),
LocalDate.parse("2021-01-05").atStartOfDay(ZoneId.systemDefault()).toInstant(), null, 3);
assertArrayEquals(expectedFilteredEvents8, realFilteredEvents8.toArray(new Event[] {}));

List<Event> realFilteredEvents9 = calendar_issue11084.getFilteredEventsBetween(
Instant.parse("2021-08-16T16:45:00.123456Z"), Instant.parse("2021-08-16T16:46:00.768643Z"), null, 3);
assertEquals(0, realFilteredEvents9.size());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
BEGIN:VCALENDAR
PRODID:-//Google Inc//Google Calendar 70.9054//EN
VERSION:2.0
CALSCALE:GREGORIAN
METHOD:PUBLISH
X-WR-CALNAME:ohtest
X-WR-TIMEZONE:UTC
BEGIN:VTIMEZONE
TZID:Europe/Brussels
X-LIC-LOCATION:Europe/Brussels
BEGIN:DAYLIGHT
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
TZNAME:CEST
DTSTART:19700329T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
TZNAME:CET
DTSTART:19701025T030000
RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
DTSTART;TZID=Europe/Brussels:20210816T184500
DTEND;TZID=Europe/Brussels:20210816T190000
DTSTAMP:20210816T174418Z
UID:[email protected]
RECURRENCE-ID;TZID=Europe/Brussels:20210816T183000
CREATED:20210816T161602Z
DESCRIPTION:BEGIN:E_Test_Cal:ON
LAST-MODIFIED:20210816T162009Z
LOCATION:
SEQUENCE:1
STATUS:CONFIRMED
SUMMARY:TEST_REPEATING_EVENT_3
TRANSP:OPAQUE
END:VEVENT
BEGIN:VEVENT
DTSTART;TZID=Europe/Brussels:20210816T183000
DTEND;TZID=Europe/Brussels:20210816T184500
RRULE:FREQ=DAILY
DTSTAMP:20210816T174418Z
UID:[email protected]
CREATED:20210816T161602Z
DESCRIPTION:BEGIN:E_Test_Cal:ON
LAST-MODIFIED:20210816T162009Z
LOCATION:
SEQUENCE:0
STATUS:CONFIRMED
SUMMARY:TEST_REPEATING_EVENT_3
TRANSP:OPAQUE
END:VEVENT
END:VCALENDAR