mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-14 17:58:59 +00:00
ALF-9156 Port the existing (SharePoint Specific) recurring events logic to Java, and add some basic tests for fetching it
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@28917 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -19,19 +19,24 @@
|
||||
package org.alfresco.repo.web.scripts.calendar;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.repo.calendar.CalendarModel;
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
import org.alfresco.service.cmr.activities.ActivityService;
|
||||
import org.alfresco.service.cmr.calendar.CalendarEntry;
|
||||
import org.alfresco.service.cmr.calendar.CalendarService;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.site.SiteInfo;
|
||||
import org.alfresco.service.cmr.site.SiteService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.GUID;
|
||||
import org.alfresco.util.ISO8601DateFormat;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
@@ -197,6 +202,27 @@ public abstract class AbstractCalendarWebScript extends DeclarativeWebScript
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* For an event that is a recurring event, have an ignored child event
|
||||
* generated for it
|
||||
*/
|
||||
protected NodeRef createIgnoreEvent(WebScriptRequest req, CalendarEntry parent)
|
||||
{
|
||||
// Get the date to be ignored
|
||||
Map<QName,Serializable> props = new HashMap<QName, Serializable>();
|
||||
Date date = parseDate(req.getParameter("date"));
|
||||
props.put(CalendarModel.PROP_IGNORE_EVENT_DATE, date);
|
||||
|
||||
// Create a child node of the event
|
||||
NodeRef ignored = nodeService.createNode(
|
||||
parent.getNodeRef(), CalendarModel.ASSOC_IGNORE_EVENT_LIST,
|
||||
QName.createQName(GUID.generate()), CalendarModel.TYPE_IGNORE_EVENT, props
|
||||
).getChildRef();
|
||||
|
||||
// No further setup is needed
|
||||
return ignored;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Object> executeImpl(WebScriptRequest req,
|
||||
Status status, Cache cache)
|
||||
|
@@ -18,16 +18,10 @@
|
||||
*/
|
||||
package org.alfresco.repo.web.scripts.calendar;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.repo.calendar.CalendarModel;
|
||||
import org.alfresco.service.cmr.calendar.CalendarEntry;
|
||||
import org.alfresco.service.cmr.site.SiteInfo;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.GUID;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.json.JSONObject;
|
||||
@@ -69,16 +63,8 @@ public class CalendarEntryDelete extends AbstractCalendarWebScript
|
||||
// Special case for "deleting" an instance of a recurring event
|
||||
if(req.getParameter("date") != null && entry.getRecurrenceRule() != null)
|
||||
{
|
||||
// Get the date to be ignored
|
||||
Map<QName,Serializable> props = new HashMap<QName, Serializable>();
|
||||
Date date = parseDate(req.getParameter("date"));
|
||||
props.put(CalendarModel.PROP_IGNORE_EVENT_DATE, date);
|
||||
|
||||
// Create a child node of the event
|
||||
nodeService.createNode(
|
||||
entry.getNodeRef(), CalendarModel.ASSOC_IGNORE_EVENT_LIST,
|
||||
QName.createQName(GUID.generate()), CalendarModel.TYPE_IGNORE_EVENT, props
|
||||
);
|
||||
// Have an ignored event generated
|
||||
createIgnoreEvent(req, entry);
|
||||
|
||||
// Mark as ignored
|
||||
status.setCode(Status.STATUS_NO_CONTENT, "Recurring entry ignored");
|
||||
|
@@ -18,13 +18,20 @@
|
||||
*/
|
||||
package org.alfresco.repo.web.scripts.calendar;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.DateFormatSymbols;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.service.cmr.calendar.CalendarEntry;
|
||||
import org.alfresco.service.cmr.calendar.CalendarEntryDTO;
|
||||
import org.alfresco.service.cmr.site.SiteInfo;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.json.JSONObject;
|
||||
import org.springframework.extensions.surf.util.I18NUtil;
|
||||
import org.springframework.extensions.webscripts.Cache;
|
||||
import org.springframework.extensions.webscripts.Status;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
@@ -37,6 +44,8 @@ import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
*/
|
||||
public class CalendarEntryGet extends AbstractCalendarWebScript
|
||||
{
|
||||
private static Log logger = LogFactory.getLog(CalendarEntryGet.class);
|
||||
|
||||
@Override
|
||||
protected Map<String, Object> executeImpl(SiteInfo site, String eventName,
|
||||
WebScriptRequest req, JSONObject json, Status status, Cache cache) {
|
||||
@@ -62,7 +71,7 @@ public class CalendarEntryGet extends AbstractCalendarWebScript
|
||||
result.put("outlookuid", entry.getOutlookUID());
|
||||
result.put("allday", CalendarEntryDTO.isAllDay(entry));
|
||||
result.put("docfolder", entry.getSharePointDocFolder());
|
||||
result.put("recurrence", null); // TODO
|
||||
result.put("recurrence", buildRecurrenceString(entry));
|
||||
|
||||
// Replace nulls with blank strings for the JSON
|
||||
for(String key : result.keySet())
|
||||
@@ -78,4 +87,141 @@ public class CalendarEntryGet extends AbstractCalendarWebScript
|
||||
model.put("result", result);
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method replicates the pre-existing behaviour for recurring events.
|
||||
* Rather than try to render the text for them on the client, we instead
|
||||
* statically render the description text here on the server.
|
||||
* When we properly support recurring events in the client (and not just
|
||||
* for SharePoint ones), this can be replaced.
|
||||
*/
|
||||
protected String buildRecurrenceString(CalendarEntry event)
|
||||
{
|
||||
// If there's no recurrence rules, then there's nothing to do
|
||||
String recurrence = event.getRecurrenceRule();
|
||||
if(recurrence == null || recurrence.trim().length() == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get our days of the week, in the current locale
|
||||
DateFormatSymbols dates = new DateFormatSymbols(I18NUtil.getLocale());
|
||||
String[] weekdays = dates.getWeekdays();
|
||||
|
||||
// And map them based on the outlook two letter codes
|
||||
Map<String,String> days = new HashMap<String, String>();
|
||||
days.put("SU", weekdays[Calendar.SUNDAY]);
|
||||
days.put("MO", weekdays[Calendar.MONDAY]);
|
||||
days.put("TU", weekdays[Calendar.TUESDAY]);
|
||||
days.put("WE", weekdays[Calendar.WEDNESDAY]);
|
||||
days.put("Th", weekdays[Calendar.THURSDAY]);
|
||||
days.put("FR", weekdays[Calendar.FRIDAY]);
|
||||
days.put("SA", weekdays[Calendar.SATURDAY]);
|
||||
|
||||
// Turn the string into a useful map
|
||||
Map<String,String> params = new HashMap<String, String>();
|
||||
for(String rule : recurrence.split(";"))
|
||||
{
|
||||
String[] parts = rule.split("=");
|
||||
if(parts.length != 2)
|
||||
{
|
||||
logger.warn("Invalid rule '" + rule + "' in recurrence: " + recurrence);
|
||||
}
|
||||
else
|
||||
{
|
||||
params.put(parts[0], parts[1]);
|
||||
}
|
||||
}
|
||||
|
||||
// To hold our result
|
||||
StringBuffer text = new StringBuffer();
|
||||
|
||||
// Handle the different frequencies
|
||||
if(params.containsKey("FREQ"))
|
||||
{
|
||||
String freq = params.get("FREQ");
|
||||
String interval = params.get("INTERVAL");
|
||||
if(interval == null)
|
||||
{
|
||||
interval = "1";
|
||||
}
|
||||
|
||||
if ("WEEKLY".equals(freq))
|
||||
{
|
||||
if ("1".equals(interval))
|
||||
{
|
||||
text.append("Occurs each week on ");
|
||||
}
|
||||
else
|
||||
{
|
||||
text.append("Occurs every " + interval + " weeks on ");
|
||||
}
|
||||
|
||||
for(String day : params.get("BYDAY").split(","))
|
||||
{
|
||||
text.append(days.get(day));
|
||||
text.append(", ");
|
||||
}
|
||||
}
|
||||
else if ("DAILY".equals(freq))
|
||||
{
|
||||
text.append("Occurs every day ");
|
||||
}
|
||||
else if ("MONTHLY".equals(freq))
|
||||
{
|
||||
if (params.get("BYMONTHDAY") != null)
|
||||
{
|
||||
text.append("Occurs day " + params.get("BYMONTHDAY"));
|
||||
}
|
||||
else if (params.get("BYSETPOS") != null)
|
||||
{
|
||||
text.append("Occurs the ");
|
||||
text.append(days.get(params.get("BYSETPOS")));
|
||||
}
|
||||
text.append(" of every " + interval + " month(s) ");
|
||||
}
|
||||
else if ("YEARLY".equals(freq))
|
||||
{
|
||||
if (params.get("BYMONTHDAY") != null)
|
||||
{
|
||||
text.append("Occurs every " + params.get("BYMONTHDAY"));
|
||||
text.append("." + params.get("BYMONTH") + " ");
|
||||
}
|
||||
else
|
||||
{
|
||||
text.append("Occurs the ");
|
||||
text.append(days.get(params.get("BYSETPOS")));
|
||||
text.append(" of " + params.get("BYMONTH") + " month ");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.warn("Unsupported recurrence frequency " + freq);
|
||||
}
|
||||
}
|
||||
|
||||
// And the rest
|
||||
DateFormat dFormat = SimpleDateFormat.getDateInstance(
|
||||
SimpleDateFormat.MEDIUM, I18NUtil.getLocale()
|
||||
);
|
||||
DateFormat tFormat = SimpleDateFormat.getTimeInstance(
|
||||
SimpleDateFormat.SHORT, I18NUtil.getLocale()
|
||||
);
|
||||
text.append("effective " + dFormat.format(event.getStart()));
|
||||
|
||||
if (params.containsKey("COUNT"))
|
||||
{
|
||||
// Nothing to do, is already handled in the recurrence date
|
||||
}
|
||||
if (event.getLastRecurrence() != null)
|
||||
{
|
||||
text.append(" until " + dFormat.format(event.getLastRecurrence()));
|
||||
}
|
||||
|
||||
text.append(" from " + tFormat.format(event.getStart()));
|
||||
text.append(" to " + tFormat.format(event.getEnd()));
|
||||
|
||||
// All done
|
||||
return text.toString();
|
||||
}
|
||||
}
|
||||
|
@@ -24,6 +24,7 @@ import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import org.alfresco.service.cmr.calendar.CalendarEntry;
|
||||
import org.alfresco.service.cmr.calendar.CalendarEntryDTO;
|
||||
import org.alfresco.service.cmr.site.SiteInfo;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -63,29 +64,24 @@ public class CalendarEntryPut extends AbstractCalendarWebScript
|
||||
// Doc folder is a bit special
|
||||
String docFolder = json.getString("docfolder");
|
||||
|
||||
if(entry.getRecurrenceRule() != null)
|
||||
// Editing recurring events is special and a little bit odd...
|
||||
if(entry.getRecurrenceRule() != null && !json.has("recurrenceRule"))
|
||||
{
|
||||
// TODO Handle editing recurring rules
|
||||
// Needs stuff with ignored events
|
||||
/*
|
||||
var prop = new Array();
|
||||
var fromParts = params.date.split("-");
|
||||
prop["ia:date"] = new Date(fromParts[0],fromParts[1] - 1,fromParts[2]);
|
||||
editedEvent.createNode(null, "ia:ignoreEvent", prop, "ia:ignoreEventList");
|
||||
|
||||
var timestamp = new Date().getTime();
|
||||
var random = Math.round(Math.random() * 10000);
|
||||
|
||||
event = eventsFolder.createNode(timestamp + "-" + random + ".ics", "ia:calendarEvent");
|
||||
event.properties["ia:isOutlook"] = true;
|
||||
|
||||
*/
|
||||
// Have an ignored event generated
|
||||
// Will allow us to override this one instance
|
||||
createIgnoreEvent(req, entry);
|
||||
|
||||
// Create a new entry for this one case
|
||||
CalendarEntry newEntry = new CalendarEntryDTO();
|
||||
newEntry.setOutlook(true);
|
||||
|
||||
// TODO Special doc folder stuff
|
||||
if("*NOT_CHANGE*".equals(docFolder))
|
||||
{
|
||||
// TODO
|
||||
newEntry.setSharePointDocFolder(entry.getSharePointDocFolder());
|
||||
}
|
||||
|
||||
// From here on, "edit" the new version
|
||||
entry = newEntry;
|
||||
}
|
||||
|
||||
// Doc folder is a bit special
|
||||
@@ -107,6 +103,32 @@ public class CalendarEntryPut extends AbstractCalendarWebScript
|
||||
// Handle the dates
|
||||
isAllDay = extractDates(entry, json);
|
||||
|
||||
// Recurring properties, only changed if keys present
|
||||
if (json.has("recurrenceRule"))
|
||||
{
|
||||
if (json.isNull("recurrenceRule"))
|
||||
{
|
||||
entry.setRecurrenceRule(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
entry.setRecurrenceRule(json.getString("recurrenceRule"));
|
||||
}
|
||||
}
|
||||
if (json.has("recurrenceLastMeeting"))
|
||||
{
|
||||
if (json.isNull("recurrenceLastMeeting"))
|
||||
{
|
||||
entry.setLastRecurrence(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
entry.setLastRecurrence(
|
||||
parseDate(json.getString("recurrenceLastMeeting"))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle tags
|
||||
if(json.has("tags"))
|
||||
{
|
||||
|
@@ -23,6 +23,7 @@ import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.site.SiteModel;
|
||||
import org.alfresco.repo.web.scripts.BaseWebScriptTest;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.security.MutableAuthenticationService;
|
||||
import org.alfresco.service.cmr.security.PersonService;
|
||||
import org.alfresco.service.cmr.site.SiteInfo;
|
||||
@@ -53,6 +54,7 @@ public class CalendarRestApiTest extends BaseWebScriptTest
|
||||
private MutableAuthenticationService authenticationService;
|
||||
private AuthenticationComponent authenticationComponent;
|
||||
private PersonService personService;
|
||||
private NodeService nodeService;
|
||||
private SiteService siteService;
|
||||
|
||||
private static final String USER_ONE = "UserOneSecondToo";
|
||||
@@ -82,6 +84,7 @@ public class CalendarRestApiTest extends BaseWebScriptTest
|
||||
this.authenticationService = (MutableAuthenticationService)getServer().getApplicationContext().getBean("AuthenticationService");
|
||||
this.authenticationComponent = (AuthenticationComponent)getServer().getApplicationContext().getBean("authenticationComponent");
|
||||
this.personService = (PersonService)getServer().getApplicationContext().getBean("PersonService");
|
||||
this.nodeService = (NodeService)getServer().getApplicationContext().getBean("NodeService");
|
||||
this.siteService = (SiteService)getServer().getApplicationContext().getBean("SiteService");
|
||||
|
||||
// Authenticate as user
|
||||
@@ -246,8 +249,8 @@ public class CalendarRestApiTest extends BaseWebScriptTest
|
||||
/**
|
||||
* Updates the event to be a 2 hour, non-all day event on the 28th of June
|
||||
*/
|
||||
public JSONObject updateEntry(String name, String what, String where, String description,
|
||||
int expectedStatus) throws Exception
|
||||
private JSONObject updateEntry(String name, String what, String where, String description,
|
||||
boolean withRecurrence, int expectedStatus) throws Exception
|
||||
{
|
||||
String date = "2011/06/28";
|
||||
String start = "11:30";
|
||||
@@ -267,6 +270,12 @@ public class CalendarRestApiTest extends BaseWebScriptTest
|
||||
json.put("docfolder", "");
|
||||
json.put("page", "calendar");
|
||||
|
||||
if(withRecurrence)
|
||||
{
|
||||
json.put("recurrenceRule", "FREQ=WEEKLY;INTERVAL=2;BYDAY=WE,FR");
|
||||
json.put("recurrenceLastMeeting", "2011-09-11");
|
||||
}
|
||||
|
||||
Response response = sendRequest(new PutRequest(URL_EVENT_BASE + name, json.toString(), "application/json"), expectedStatus);
|
||||
if (expectedStatus == Status.STATUS_OK)
|
||||
{
|
||||
@@ -370,7 +379,7 @@ public class CalendarRestApiTest extends BaseWebScriptTest
|
||||
|
||||
|
||||
// Edit
|
||||
entry = updateEntry(name, EVENT_TITLE_ONE, "More Where", "More Thing", Status.STATUS_OK);
|
||||
entry = updateEntry(name, EVENT_TITLE_ONE, "More Where", "More Thing", false, Status.STATUS_OK);
|
||||
assertEquals("Error found " + entry.toString(), false, entry.has("error"));
|
||||
assertEquals(EVENT_TITLE_ONE, entry.getString("summary"));
|
||||
assertEquals("More Where", entry.getString("location"));
|
||||
@@ -403,6 +412,31 @@ public class CalendarRestApiTest extends BaseWebScriptTest
|
||||
// TODO Make it a whole day event and check that
|
||||
|
||||
|
||||
// Make it recurring
|
||||
entry = updateEntry(name, EVENT_TITLE_ONE, "More Where", "More Thing", true, Status.STATUS_OK);
|
||||
|
||||
// Fetch
|
||||
entry = getEntry(name, Status.STATUS_OK);
|
||||
|
||||
assertEquals("Error found " + entry.toString(), false, entry.has("error"));
|
||||
assertEquals(EVENT_TITLE_ONE, entry.getString("what"));
|
||||
assertEquals(name, entry.getString("name"));
|
||||
assertEquals("More Where", entry.getString("location")); // Not where...
|
||||
assertEquals("More Thing", entry.getString("description"));
|
||||
|
||||
assertEquals("false", entry.getString("isoutlook"));
|
||||
assertEquals("6/28/2011", entry.getString("from"));
|
||||
assertEquals("6/28/2011", entry.getString("to"));
|
||||
assertEquals("11:30", entry.getString("start"));
|
||||
assertEquals("13:30", entry.getString("end"));
|
||||
assertEquals("false", entry.getString("allday"));
|
||||
assertEquals(
|
||||
"Occurs every 2 weeks on Wednesday, Friday, effective " +
|
||||
"28-Jun-2011 until 11-Sep-2011 from 11:30 to 13:30",
|
||||
entry.getString("recurrence")
|
||||
);
|
||||
|
||||
|
||||
// Delete
|
||||
sendRequest(new DeleteRequest(URL_EVENT_BASE + name), Status.STATUS_NO_CONTENT);
|
||||
|
||||
@@ -453,7 +487,7 @@ public class CalendarRestApiTest extends BaseWebScriptTest
|
||||
// Add a third, on the next day
|
||||
JSONObject entry = createEntry(EVENT_TITLE_THREE, "Where3", "Thing 3", Status.STATUS_OK);
|
||||
String name3 = getNameFromEntry(entry);
|
||||
updateEntry(name3, EVENT_TITLE_THREE, "More Where 3", "More Thing 3", Status.STATUS_OK);
|
||||
updateEntry(name3, EVENT_TITLE_THREE, "More Where 3", "More Thing 3", false, Status.STATUS_OK);
|
||||
|
||||
|
||||
// Check now, should have two days
|
||||
@@ -506,7 +540,7 @@ public class CalendarRestApiTest extends BaseWebScriptTest
|
||||
// Add a third, on the next day
|
||||
JSONObject entry = createEntry(EVENT_TITLE_THREE, "Where3", "Thing 3", Status.STATUS_OK);
|
||||
String name3 = getNameFromEntry(entry);
|
||||
updateEntry(name3, EVENT_TITLE_THREE, "More Where 3", "More Thing 3", Status.STATUS_OK);
|
||||
updateEntry(name3, EVENT_TITLE_THREE, "More Where 3", "More Thing 3", false, Status.STATUS_OK);
|
||||
|
||||
|
||||
// Check getting all of them
|
||||
|
Reference in New Issue
Block a user