diff --git a/source/java/org/alfresco/repo/web/scripts/calendar/AllCalendarTests.java b/source/java/org/alfresco/repo/web/scripts/calendar/AllCalendarTests.java index 4eb5bdfc74..a4afd32ecf 100644 --- a/source/java/org/alfresco/repo/web/scripts/calendar/AllCalendarTests.java +++ b/source/java/org/alfresco/repo/web/scripts/calendar/AllCalendarTests.java @@ -18,6 +18,7 @@ */ package org.alfresco.repo.web.scripts.calendar; +import org.alfresco.repo.calendar.CalendarHelpersTest; import org.alfresco.repo.calendar.CalendarServiceImplTest; import org.alfresco.service.cmr.calendar.CalendarService; import org.junit.runner.RunWith; @@ -34,6 +35,7 @@ import org.junit.runners.Suite; @RunWith(Suite.class) @Suite.SuiteClasses({ CalendarServiceImplTest.class, + CalendarHelpersTest.class, CalendarRestApiTest.class }) public class AllCalendarTests diff --git a/source/java/org/alfresco/repo/web/scripts/calendar/CalendarRestApiTest.java b/source/java/org/alfresco/repo/web/scripts/calendar/CalendarRestApiTest.java index 63e5e93f23..74a3ef5807 100644 --- a/source/java/org/alfresco/repo/web/scripts/calendar/CalendarRestApiTest.java +++ b/source/java/org/alfresco/repo/web/scripts/calendar/CalendarRestApiTest.java @@ -211,7 +211,7 @@ public class CalendarRestApiTest extends BaseWebScriptTest int expectedStatus) throws Exception { - String date = "2011/06/29"; + String date = "2011/06/29"; // A wednesday String start = "12:00"; String end = "13:00"; @@ -252,7 +252,7 @@ public class CalendarRestApiTest extends BaseWebScriptTest private JSONObject updateEntry(String name, String what, String where, String description, boolean withRecurrence, int expectedStatus) throws Exception { - String date = "2011/06/28"; + String date = "2011/06/28"; // A Tuesday String start = "11:30"; String end = "13:30"; @@ -530,7 +530,13 @@ public class CalendarRestApiTest extends BaseWebScriptTest result = getEntries(null, null); assertEquals(1, result.length()); - result = getEntries("admin", "2000/01/01"); // TODO From date shouldn't be needed... + result = getEntries("admin", "2000/01/01"); // With a from date + events = result.getJSONArray("events"); + assertEquals(2, events.length()); + assertEquals(EVENT_TITLE_ONE, events.getJSONObject(0).getString("title")); + assertEquals(EVENT_TITLE_TWO, events.getJSONObject(1).getString("title")); + + result = getEntries("admin", null); // Without a from date events = result.getJSONArray("events"); assertEquals(2, events.length()); assertEquals(EVENT_TITLE_ONE, events.getJSONObject(0).getString("title")); @@ -587,5 +593,79 @@ public class CalendarRestApiTest extends BaseWebScriptTest events = result.getJSONArray("events"); assertEquals(0, events.length()); } - + + /** + * Repeating events support + */ + public void testRepeatingEventsInUserListing() throws Exception + { + JSONObject result; + JSONArray events; + + // Initially, there are no events + result = getEntries(null, null); + assertEquals(0, result.length()); + + result = getEntries("admin", null); + events = result.getJSONArray("events"); + assertEquals(0, events.length()); + + // Add two events in the past, one of which repeats + JSONObject entry1 = createEntry(EVENT_TITLE_ONE, "Somewhere", "Thing 1", Status.STATUS_OK); + JSONObject entry2 = createEntry(EVENT_TITLE_TWO, "Somewhere", "Thing 2", Status.STATUS_OK); + String entryName1 = getNameFromEntry(entry1); + String entryName2 = getNameFromEntry(entry2); + // Have it repeat on wednesdays and fridays every two weeks + updateEntry(entryName2, EVENT_TITLE_TWO, "Somewhere", "Thing 2", true, Status.STATUS_OK); + + + // Get all the entries, without repeats expanded + result = getEntries("admin", "2011-06-27"); + events = result.getJSONArray("events"); + assertEquals(2, events.length()); + assertEquals(entryName2, events.getJSONObject(0).getString("name")); + assertEquals(entryName1, events.getJSONObject(1).getString("name")); + assertEquals(EVENT_TITLE_TWO + " (Repeating)", events.getJSONObject(0).getString("title")); + assertEquals(EVENT_TITLE_ONE, events.getJSONObject(1).getString("title")); + + + // Get all the entries, with repeats expanded + result = getEntries("admin", "2011/06/27"); + events = result.getJSONArray("events"); + assertEquals(7, Math.min(events.length(),7)); // At least + assertEquals(entryName2, events.getJSONObject(0).getString("name")); + assertEquals(entryName2, events.getJSONObject(1).getString("name")); // 11:30 -> + assertEquals(entryName1, events.getJSONObject(2).getString("name")); // 12:00 -> + assertEquals(entryName2, events.getJSONObject(3).getString("name")); + assertEquals(entryName2, events.getJSONObject(4).getString("name")); + assertEquals(entryName2, events.getJSONObject(5).getString("name")); + assertEquals(entryName2, events.getJSONObject(6).getString("name")); + assertEquals(entryName2, events.getJSONObject(7).getString("name")); + assertEquals(EVENT_TITLE_TWO, events.getJSONObject(0).getString("title")); + assertEquals(EVENT_TITLE_TWO, events.getJSONObject(1).getString("title")); + assertEquals(EVENT_TITLE_ONE, events.getJSONObject(2).getString("title")); + assertEquals(EVENT_TITLE_TWO, events.getJSONObject(3).getString("title")); + assertEquals(EVENT_TITLE_TWO, events.getJSONObject(4).getString("title")); + assertEquals(EVENT_TITLE_TWO, events.getJSONObject(5).getString("title")); + assertEquals(EVENT_TITLE_TWO, events.getJSONObject(6).getString("title")); + assertEquals(EVENT_TITLE_TWO, events.getJSONObject(7).getString("title")); + + // Check the dates on these: + // Repeating original + assertEquals("2011-06-28T", events.getJSONObject(0).getJSONObject("startAt").getString("iso8601").substring(0,11)); + // 1st repeat Wednesday + assertEquals("2011-06-29T", events.getJSONObject(1).getJSONObject("startAt").getString("iso8601").substring(0,11)); + // Non-repeating original + assertEquals("2011-06-29T", events.getJSONObject(2).getJSONObject("startAt").getString("iso8601").substring(0,11)); + // 1st repeat Friday + assertEquals("2011-07-01T", events.getJSONObject(3).getJSONObject("startAt").getString("iso8601").substring(0,11)); + // 2nd repeat Wednesday + assertEquals("2011-07-13T", events.getJSONObject(4).getJSONObject("startAt").getString("iso8601").substring(0,11)); + // 2nd repeat Friday + assertEquals("2011-07-15T", events.getJSONObject(5).getJSONObject("startAt").getString("iso8601").substring(0,11)); + // 3rd repeat Wednesday + assertEquals("2011-07-27T", events.getJSONObject(6).getJSONObject("startAt").getString("iso8601").substring(0,11)); + // 3rd repeat Friday + assertEquals("2011-07-29T", events.getJSONObject(7).getJSONObject("startAt").getString("iso8601").substring(0,11)); + } } \ No newline at end of file diff --git a/source/java/org/alfresco/repo/web/scripts/calendar/UserCalendarEntriesGet.java b/source/java/org/alfresco/repo/web/scripts/calendar/UserCalendarEntriesGet.java index eadcb18dc3..781f5ec518 100644 --- a/source/java/org/alfresco/repo/web/scripts/calendar/UserCalendarEntriesGet.java +++ b/source/java/org/alfresco/repo/web/scripts/calendar/UserCalendarEntriesGet.java @@ -19,6 +19,9 @@ package org.alfresco.repo.web.scripts.calendar; import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -77,21 +80,37 @@ public class UserCalendarEntriesGet extends AbstractCalendarWebScript // What should we do about repeating events? First or all? boolean repeatingFirstOnly = true; - if(fromDate != null) + String repeatingEvents = req.getParameter("repeating"); + if(repeatingEvents != null) { - // TODO Find a better way to do this... - String fromDateS = req.getParameter("from"); - if(fromDateS.indexOf('-') != -1) + if("first".equals(repeatingEvents)) { - // Apparently this is the site calendar dashlet... repeatingFirstOnly = true; } - if(fromDateS.indexOf('/') != -1) + else if("all".equals(repeatingEvents)) { - // This is something else, wants all events in range repeatingFirstOnly = false; } } + else + { + // Fall back to the icky old way of guessing it from + // the format of the from date, which differs between uses! + if(fromDate != null) + { + String fromDateS = req.getParameter("from"); + if(fromDateS.indexOf('-') != -1) + { + // Apparently this is the site calendar dashlet... + repeatingFirstOnly = true; + } + if(fromDateS.indexOf('/') != -1) + { + // This is something else, wants all events in range + repeatingFirstOnly = false; + } + } + } // One site, or all the user's ones? List sites = new ArrayList(); @@ -125,6 +144,7 @@ public class UserCalendarEntriesGet extends AbstractCalendarWebScript PagingResults entries = calendarService.listCalendarEntries(siteShortNames, fromDate, toDate, paging); + boolean resortNeeded = false; List> results = new ArrayList>(); for(CalendarEntry entry : entries.getPage()) { @@ -160,7 +180,39 @@ public class UserCalendarEntriesGet extends AbstractCalendarWebScript results.add(result); // Handle recurring as needed - handleRecurring(entry, result, results, fromDate, repeatingFirstOnly); + boolean orderChanged = handleRecurring(entry, result, results, fromDate, repeatingFirstOnly); + if(orderChanged) + { + resortNeeded = true; + } + } + + // If the recurring events meant dates changed, re-sort + if(resortNeeded) + { + Collections.sort(results, new Comparator>() { + public int compare(Map resultA, + Map resultB) { + Date startA = (Date)resultA.get(RESULT_START); + Date startB = (Date)resultB.get(RESULT_START); + + int cmp = startA.compareTo(startB); + if(cmp == 0) + { + Date endA = (Date)resultA.get(RESULT_END); + Date endB = (Date)resultB.get(RESULT_END); + cmp = endA.compareTo(endB); + if(cmp == 0) + { + String nameA = (String)resultA.get(RESULT_NAME); + String nameB = (String)resultB.get(RESULT_NAME); + return nameA.compareTo(nameB); + } + return cmp; + } + return cmp; + } + }); } // All done @@ -230,23 +282,29 @@ public class UserCalendarEntriesGet extends AbstractCalendarWebScript } /** - * Do what's needed for recurring events + * Do what's needed for recurring events. + * + * @return If dates have been tweaked, and a sort may be required */ - private void handleRecurring(CalendarEntry entry, Map entryResult, + private boolean handleRecurring(CalendarEntry entry, Map entryResult, List> allResults, Date from, boolean repeatingFirstOnly) { if(entry.getRecurrenceRule() == null) { // Nothing to do - return; + return false; } // Should we limit ourselves? Date until = null; if(!repeatingFirstOnly) { - // Only repeating instances for the next 60 days - until = new Date(from.getTime() + 24*60*60*1000); + // Only repeating instances for the next 60 days, to keep the list sane + // (It's normally only used for a month view anyway) + Calendar c = Calendar.getInstance(); + c.setTime(from); + c.add(Calendar.DATE, 60); + until = c.getTime(); } // How long is it? @@ -255,12 +313,26 @@ public class UserCalendarEntriesGet extends AbstractCalendarWebScript // Get it's recurring instances List dates = CalendarRecurrenceHelper.getRecurrencesOnOrAfter( entry, from, until, repeatingFirstOnly); + if(dates == null) + { + dates = new ArrayList(); + } + + // Add on the original event time itself if needed + if(entry.getStart().getTime() >= from.getTime()) + { + if(dates.size() == 0 || dates.get(0).getTime() != entry.getStart().getTime()) + { + // Original event is after the start time, and not on the recurring list + dates.add(0, entry.getStart()); + } + } // If we got no dates, then no recurrences in the period so zap - if(dates == null || dates.size() == 0) + if(dates.size() == 0) { allResults.remove(entryResult); - return; + return false; // Remains sorted despite delete } // Always update the live entry @@ -270,7 +342,7 @@ public class UserCalendarEntriesGet extends AbstractCalendarWebScript if(repeatingFirstOnly) { entryResult.put(RESULT_TITLE, entry.getTitle() + " (Repeating)"); - return; + return true; // Date has been changed } // Otherwise generate one entry per extra date @@ -285,6 +357,9 @@ public class UserCalendarEntriesGet extends AbstractCalendarWebScript // Save as a new event allResults.add(newResult); } + + // New dates have been added + return true; } private void updateRepeatingStartEnd(Date newStart, long duration, Map result)