ALF-9156 Finish recurring event support in the calendar listing webscript, and add in new unit tests to cover this case

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@29235 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Nick Burch
2011-07-20 17:44:55 +00:00
parent 5a303b71ec
commit 6b7ba3f6c1
3 changed files with 177 additions and 20 deletions

View File

@@ -18,6 +18,7 @@
*/ */
package org.alfresco.repo.web.scripts.calendar; package org.alfresco.repo.web.scripts.calendar;
import org.alfresco.repo.calendar.CalendarHelpersTest;
import org.alfresco.repo.calendar.CalendarServiceImplTest; import org.alfresco.repo.calendar.CalendarServiceImplTest;
import org.alfresco.service.cmr.calendar.CalendarService; import org.alfresco.service.cmr.calendar.CalendarService;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@@ -34,6 +35,7 @@ import org.junit.runners.Suite;
@RunWith(Suite.class) @RunWith(Suite.class)
@Suite.SuiteClasses({ @Suite.SuiteClasses({
CalendarServiceImplTest.class, CalendarServiceImplTest.class,
CalendarHelpersTest.class,
CalendarRestApiTest.class CalendarRestApiTest.class
}) })
public class AllCalendarTests public class AllCalendarTests

View File

@@ -211,7 +211,7 @@ public class CalendarRestApiTest extends BaseWebScriptTest
int expectedStatus) int expectedStatus)
throws Exception throws Exception
{ {
String date = "2011/06/29"; String date = "2011/06/29"; // A wednesday
String start = "12:00"; String start = "12:00";
String end = "13: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, private JSONObject updateEntry(String name, String what, String where, String description,
boolean withRecurrence, int expectedStatus) throws Exception boolean withRecurrence, int expectedStatus) throws Exception
{ {
String date = "2011/06/28"; String date = "2011/06/28"; // A Tuesday
String start = "11:30"; String start = "11:30";
String end = "13:30"; String end = "13:30";
@@ -530,7 +530,13 @@ public class CalendarRestApiTest extends BaseWebScriptTest
result = getEntries(null, null); result = getEntries(null, null);
assertEquals(1, result.length()); 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"); events = result.getJSONArray("events");
assertEquals(2, events.length()); assertEquals(2, events.length());
assertEquals(EVENT_TITLE_ONE, events.getJSONObject(0).getString("title")); assertEquals(EVENT_TITLE_ONE, events.getJSONObject(0).getString("title"));
@@ -587,5 +593,79 @@ public class CalendarRestApiTest extends BaseWebScriptTest
events = result.getJSONArray("events"); events = result.getJSONArray("events");
assertEquals(0, events.length()); 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));
}
} }

View File

@@ -19,6 +19,9 @@
package org.alfresco.repo.web.scripts.calendar; package org.alfresco.repo.web.scripts.calendar;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@@ -77,21 +80,37 @@ public class UserCalendarEntriesGet extends AbstractCalendarWebScript
// What should we do about repeating events? First or all? // What should we do about repeating events? First or all?
boolean repeatingFirstOnly = true; boolean repeatingFirstOnly = true;
if(fromDate != null) String repeatingEvents = req.getParameter("repeating");
if(repeatingEvents != null)
{ {
// TODO Find a better way to do this... if("first".equals(repeatingEvents))
String fromDateS = req.getParameter("from");
if(fromDateS.indexOf('-') != -1)
{ {
// Apparently this is the site calendar dashlet...
repeatingFirstOnly = true; repeatingFirstOnly = true;
} }
if(fromDateS.indexOf('/') != -1) else if("all".equals(repeatingEvents))
{ {
// This is something else, wants all events in range
repeatingFirstOnly = false; 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? // One site, or all the user's ones?
List<SiteInfo> sites = new ArrayList<SiteInfo>(); List<SiteInfo> sites = new ArrayList<SiteInfo>();
@@ -125,6 +144,7 @@ public class UserCalendarEntriesGet extends AbstractCalendarWebScript
PagingResults<CalendarEntry> entries = PagingResults<CalendarEntry> entries =
calendarService.listCalendarEntries(siteShortNames, fromDate, toDate, paging); calendarService.listCalendarEntries(siteShortNames, fromDate, toDate, paging);
boolean resortNeeded = false;
List<Map<String, Object>> results = new ArrayList<Map<String,Object>>(); List<Map<String, Object>> results = new ArrayList<Map<String,Object>>();
for(CalendarEntry entry : entries.getPage()) for(CalendarEntry entry : entries.getPage())
{ {
@@ -160,7 +180,39 @@ public class UserCalendarEntriesGet extends AbstractCalendarWebScript
results.add(result); results.add(result);
// Handle recurring as needed // 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<Map<String, Object>>() {
public int compare(Map<String, Object> resultA,
Map<String, Object> 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 // 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<String, Object> entryResult, private boolean handleRecurring(CalendarEntry entry, Map<String, Object> entryResult,
List<Map<String, Object>> allResults, Date from, boolean repeatingFirstOnly) List<Map<String, Object>> allResults, Date from, boolean repeatingFirstOnly)
{ {
if(entry.getRecurrenceRule() == null) if(entry.getRecurrenceRule() == null)
{ {
// Nothing to do // Nothing to do
return; return false;
} }
// Should we limit ourselves? // Should we limit ourselves?
Date until = null; Date until = null;
if(!repeatingFirstOnly) if(!repeatingFirstOnly)
{ {
// Only repeating instances for the next 60 days // Only repeating instances for the next 60 days, to keep the list sane
until = new Date(from.getTime() + 24*60*60*1000); // (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? // How long is it?
@@ -255,12 +313,26 @@ public class UserCalendarEntriesGet extends AbstractCalendarWebScript
// Get it's recurring instances // Get it's recurring instances
List<Date> dates = CalendarRecurrenceHelper.getRecurrencesOnOrAfter( List<Date> dates = CalendarRecurrenceHelper.getRecurrencesOnOrAfter(
entry, from, until, repeatingFirstOnly); entry, from, until, repeatingFirstOnly);
if(dates == null)
{
dates = new ArrayList<Date>();
}
// 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 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); allResults.remove(entryResult);
return; return false; // Remains sorted despite delete
} }
// Always update the live entry // Always update the live entry
@@ -270,7 +342,7 @@ public class UserCalendarEntriesGet extends AbstractCalendarWebScript
if(repeatingFirstOnly) if(repeatingFirstOnly)
{ {
entryResult.put(RESULT_TITLE, entry.getTitle() + " (Repeating)"); entryResult.put(RESULT_TITLE, entry.getTitle() + " (Repeating)");
return; return true; // Date has been changed
} }
// Otherwise generate one entry per extra date // Otherwise generate one entry per extra date
@@ -285,6 +357,9 @@ public class UserCalendarEntriesGet extends AbstractCalendarWebScript
// Save as a new event // Save as a new event
allResults.add(newResult); allResults.add(newResult);
} }
// New dates have been added
return true;
} }
private void updateRepeatingStartEnd(Date newStart, long duration, Map<String, Object> result) private void updateRepeatingStartEnd(Date newStart, long duration, Map<String, Object> result)