diff --git a/calendar/calendar-api/api/src/java/org/sakaiproject/calendar/api/CalendarService.java b/calendar/calendar-api/api/src/java/org/sakaiproject/calendar/api/CalendarService.java index 203f82dd3608..569693d6a4c2 100644 --- a/calendar/calendar-api/api/src/java/org/sakaiproject/calendar/api/CalendarService.java +++ b/calendar/calendar-api/api/src/java/org/sakaiproject/calendar/api/CalendarService.java @@ -358,7 +358,7 @@ public void removeCalendar(CalendarEdit edit) * Takes several calendar References and merges their events from within a given time range. * * @param references The List of calendar References. - * @param range The time period to use to select events. If this is null, all times will be retrieved + * @param range The time period to use to select events. If this is null, one year before and after will be used. * @return CalendarEventVector object with the union of all events from the list of calendars in the given time range. */ public CalendarEventVector getEvents(List references, TimeRange range); @@ -367,7 +367,7 @@ public void removeCalendar(CalendarEdit edit) * Takes several calendar References and merges their events from within a given time range. * * @param references The List of calendar References. - * @param range The time period to use to select events. If this is null, all times will be retrieved + * @param range The time period to use to select events. If this is null, one year before and after will be used. * @param reverseOrder CalendarEventVector object will be ordered reverse. * @return CalendarEventVector object with the union of all events from the list of calendars in the given time range. */ diff --git a/calendar/calendar-impl/impl/src/java/org/sakaiproject/calendar/impl/BaseCalendarService.java b/calendar/calendar-impl/impl/src/java/org/sakaiproject/calendar/impl/BaseCalendarService.java index 9c17c10b7483..b142f5201447 100644 --- a/calendar/calendar-impl/impl/src/java/org/sakaiproject/calendar/impl/BaseCalendarService.java +++ b/calendar/calendar-impl/impl/src/java/org/sakaiproject/calendar/impl/BaseCalendarService.java @@ -321,7 +321,7 @@ public CalendarEventVector getEvents(List references, TimeRange range, boolean r if (references != null) { if (range == null) { - range = m_timeService.newTimeRange(Instant.EPOCH, Instant.MAX); + range = getOneYearTimeRange(); } List allEvents = new ArrayList(); @@ -385,7 +385,7 @@ private List getEvents(List references, TimeRange range, if (references != null) { if (range == null) { - range = m_timeService.newTimeRange(Instant.EPOCH, Instant.MAX); + range = getOneYearTimeRange(); } for (String ref : references) { try { @@ -5947,6 +5947,17 @@ public boolean isCalendarToolInitialized(String siteId){ return true; } + // Private helper method to generate a time range one year before and one year after the current time + private TimeRange getOneYearTimeRange() { + Instant now = Instant.now(); + + // Create a time range from one year ago to one year from now + Instant oneYearAgo = now.minus(365, ChronoUnit.DAYS); + Instant oneYearLater = now.plus(365, ChronoUnit.DAYS); + + return m_timeService.newTimeRange(oneYearAgo, oneYearLater); + } + private String getDirectToolUrl(String siteId) throws IdUnusedException { ToolConfiguration toolConfig = m_siteService.getSite(siteId).getToolForCommonId("sakai.schedule"); return m_serverConfigurationService.getPortalUrl() + "/directtool/" + toolConfig.getId(); diff --git a/calendar/calendar-impl/impl/src/java/org/sakaiproject/calendar/impl/RecurrenceRuleBase.java b/calendar/calendar-impl/impl/src/java/org/sakaiproject/calendar/impl/RecurrenceRuleBase.java index e2dbe82a88bf..ee7bbcec26a6 100644 --- a/calendar/calendar-impl/impl/src/java/org/sakaiproject/calendar/impl/RecurrenceRuleBase.java +++ b/calendar/calendar-impl/impl/src/java/org/sakaiproject/calendar/impl/RecurrenceRuleBase.java @@ -27,6 +27,7 @@ import java.util.TimeZone; import java.util.Vector; +import lombok.extern.slf4j.Slf4j; import org.w3c.dom.Element; import org.xml.sax.Attributes; @@ -44,6 +45,7 @@ /** * This is a common base for the daily, weekly, monthly, and yearly recurrence rules. */ +@Slf4j public abstract class RecurrenceRuleBase implements RecurrenceRule { /** Every this many number of units: 1 would be daily/monthly/annually. */ @@ -103,7 +105,7 @@ public RecurrenceRuleBase(int interval, Time until) * @param range A time range to limit the generated ranges. * @param timeZone The time zone to use for displaying times. * %%% Note: this is currently not implemented, and always uses the "local" zone. - * @return a List of RecurrenceInstance generated by this rule in this range. + * @return a List of max 1000 RecurrenceInstance generated by this rule in this range. */ public List generateInstances(TimeRange prototype, TimeRange range, TimeZone timeZone) { @@ -149,6 +151,7 @@ public List generateInstances(TimeRange prototype, TimeRange range, TimeZone tim (GregorianCalendar) startCalendarDate.clone(); int currentCount = 1; + int maxItems = 1000; do { @@ -189,11 +192,20 @@ public List generateInstances(TimeRange prototype, TimeRange range, TimeZone tim // use this one rv.add(new RecurrenceInstance(eventTimeRange, currentCount)); + + // Break if we reach the max limit + if (rv.size() >= maxItems) + { + log.warn("Reached the maximum limit of 1000 items for recurring events."); + break; + } } // if next starts after the range, stop generating else if (isAfter(nextTime, range.lastTime())) - break; + { + break; + } // advance interval years. diff --git a/kernel/kernel-impl/src/main/java/org/sakaiproject/time/impl/BasicTimeService.java b/kernel/kernel-impl/src/main/java/org/sakaiproject/time/impl/BasicTimeService.java index 07ab18a7aa3d..1592a521ca07 100644 --- a/kernel/kernel-impl/src/main/java/org/sakaiproject/time/impl/BasicTimeService.java +++ b/kernel/kernel-impl/src/main/java/org/sakaiproject/time/impl/BasicTimeService.java @@ -310,7 +310,7 @@ public TimeRange newTimeRange(Time start, Time end) public TimeRange newTimeRange(Instant start, Instant end) { - return new MyTimeRange(newTime(start.getEpochSecond()), newTime(end.getEpochSecond())); + return new MyTimeRange(newTime(start.toEpochMilli()), newTime(end.toEpochMilli())); } @Override diff --git a/kernel/kernel-impl/src/test/java/org/sakaiproject/time/impl/test/BaseTimeServiceTest.java b/kernel/kernel-impl/src/test/java/org/sakaiproject/time/impl/test/BaseTimeServiceTest.java index b9fc28455131..811bf0dc4b1f 100644 --- a/kernel/kernel-impl/src/test/java/org/sakaiproject/time/impl/test/BaseTimeServiceTest.java +++ b/kernel/kernel-impl/src/test/java/org/sakaiproject/time/impl/test/BaseTimeServiceTest.java @@ -26,7 +26,11 @@ import org.sakaiproject.time.impl.MyTime; import org.sakaiproject.time.impl.BasicTimeService.MyTimeRange; +import java.time.Instant; + import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -70,4 +74,48 @@ public void testDurtation() { assertEquals(tr1.duration(),42l); } + @Test + public void newTimeRange_withValidInstants_shouldReturnCorrectTimeRange() { + BasicTimeService timeService = new BasicTimeService(); + Instant start = Instant.parse("2023-01-01T00:00:00Z"); + Instant end = Instant.parse("2023-01-02T00:00:00Z"); + + TimeRange timeRange = timeService.newTimeRange(start, end); + + assertNotNull(timeRange); + assertEquals(start.toEpochMilli(), timeRange.firstTime().getTime()); + assertEquals(end.toEpochMilli(), timeRange.lastTime().getTime()); + + // The duration should be 1 day + assertEquals(timeRange.duration(), 86400000); + } + + @Test + public void newTimeRange_withStartAfterEnd_shouldSwapTimes() { + BasicTimeService timeService = new BasicTimeService(); + Instant start = Instant.parse("2023-01-02T00:00:00Z"); + Instant end = Instant.parse("2023-01-01T00:00:00Z"); + + TimeRange timeRange = timeService.newTimeRange(start, end); + + assertNotNull(timeRange); + assertEquals(end.toEpochMilli(), timeRange.firstTime().getTime()); + assertEquals(start.toEpochMilli(), timeRange.lastTime().getTime()); + } + + @Test + public void newTimeRange_withSameStartAndEnd_shouldReturnSingleTimeRange() { + BasicTimeService timeService = new BasicTimeService(); + Instant start = Instant.parse("2023-01-01T00:00:00Z"); + + TimeRange timeRange = timeService.newTimeRange(start, start); + + assertNotNull(timeRange); + assertEquals(start.toEpochMilli(), timeRange.firstTime().getTime()); + assertEquals(start.toEpochMilli(), timeRange.lastTime().getTime()); + assertTrue(timeRange.isSingleTime()); + + // Duration should be 0 + assertEquals(timeRange.duration(), 0); + } }