diff --git a/config/alfresco/templates/webscripts/org/alfresco/presence/config.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/presence/config.get.desc.xml
new file mode 100644
index 0000000000..6cbac029b6
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/presence/config.get.desc.xml
@@ -0,0 +1,8 @@
+
+ Presence Custom View Configuration
+ Add webscript aspect to space node
+ /ui/presence/config?n={nodeRef}&w={webscriptUrl}
+
+ user
+ required
+
diff --git a/config/alfresco/templates/webscripts/org/alfresco/presence/config.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/presence/config.get.html.ftl
new file mode 100644
index 0000000000..1fd65886eb
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/presence/config.get.html.ftl
@@ -0,0 +1,54 @@
+
+
+
+ Online Presence Space Configurator
+
+
+
+Online Presence Space Configurator
+
+
+<#if args.n?exists>
+ Aspect added to space.
+#if>
+
+
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/presence/config.get.js b/config/alfresco/templates/webscripts/org/alfresco/presence/config.get.js
new file mode 100644
index 0000000000..5fc65fea3f
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/presence/config.get.js
@@ -0,0 +1,7 @@
+if (args["n"] != null)
+{
+ var dest = search.findNode(args["n"]);
+ dest.addAspect("cm:webscriptable");
+ dest.properties["cm:webscript"] = args["w"];
+ dest.save();
+}
diff --git a/config/alfresco/templates/webscripts/org/alfresco/presence/status.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/presence/status.get.desc.xml
new file mode 100644
index 0000000000..234a25b79c
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/presence/status.get.desc.xml
@@ -0,0 +1,8 @@
+
+ Presence Custom View
+ Show online presence status of space users
+ /ui/presence/status?nodeRef={noderef}
+
+ user
+ required
+
diff --git a/config/alfresco/templates/webscripts/org/alfresco/presence/status.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/presence/status.get.html.ftl
new file mode 100644
index 0000000000..dda7864173
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/presence/status.get.html.ftl
@@ -0,0 +1,70 @@
+
+
+Invited Users Presence Status
+
+

=online
+

=offline
+

=unknown
+
+
+<#list presenceResults as pr>
+
+#list>
+
+
+
diff --git a/config/alfresco/templates/webscripts/org/alfresco/presence/status.get.js b/config/alfresco/templates/webscripts/org/alfresco/presence/status.get.js
new file mode 100644
index 0000000000..91c94205ed
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/presence/status.get.js
@@ -0,0 +1,53 @@
+main();
+
+function main()
+{
+ var nodeRef = args["nodeRef"];
+ var space = search.findNode(nodeRef);
+ var tokens, user, group;
+ var results = new Array();
+
+ for each(perm in space.permissions)
+ {
+ tokens = perm.split(";");
+ if (tokens[0] == "ALLOWED")
+ {
+ if (("CollaboratorContributorCoordinatorEditor").indexOf(tokens[2]) != -1)
+ {
+ user = people.getPerson(tokens[1]);
+ if (user != null)
+ {
+ pushUnique(results, user, presence.getDetails(user));
+ }
+ else
+ {
+ group = people.getGroup(tokens[1]);
+ if (group != null)
+ {
+ for each(user in people.getMembers(group))
+ {
+ pushUnique(results, user, presence.getDetails(user));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ model.space = space;
+ model.presenceResults = results;
+}
+
+function pushUnique(results, user, details)
+{
+ var fullName = user.properties["firstName"] + " " + user.properties["lastName"];
+
+ for (i=0; i < results.length; i++)
+ {
+ if (results[i][0] == fullName)
+ {
+ return;
+ }
+ }
+ results.push(new Array(fullName, details));
+}
diff --git a/source/java/org/alfresco/web/bean/ajax/PresenceProxyBean.java b/source/java/org/alfresco/web/bean/ajax/PresenceProxyBean.java
new file mode 100644
index 0000000000..6dd48fc37b
--- /dev/null
+++ b/source/java/org/alfresco/web/bean/ajax/PresenceProxyBean.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing
+ */
+package org.alfresco.web.bean.ajax;
+
+import java.io.IOException;
+import java.util.Map;
+
+import javax.faces.context.FacesContext;
+import javax.faces.context.ResponseWriter;
+
+import org.alfresco.repo.content.MimetypeMap;
+import org.alfresco.web.app.servlet.ajax.InvokeCommand;
+import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpException;
+import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.HttpStatus;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.httpclient.params.HttpMethodParams;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Bean which proxies requests to online presence servers.
+ *
+ * @author Mike Hatfield
+ */
+public class PresenceProxyBean
+{
+ private static Log logger = LogFactory.getLog(PresenceProxyBean.class);
+
+ @InvokeCommand.ResponseMimetype(value=MimetypeMap.MIMETYPE_HTML)
+ public void proxyRequest() throws Exception
+ {
+ FacesContext fc = FacesContext.getCurrentInstance();
+ ResponseWriter out = fc.getResponseWriter();
+
+ Map requestMap = fc.getExternalContext().getRequestParameterMap();
+ String url = (String)requestMap.get("url");
+
+ if (logger.isDebugEnabled())
+ logger.debug("PresenceProxyBean.proxyRequest() url=" + url);
+
+ if (url != null)
+ {
+ String response = getUrlResponse(url);
+ out.write(response);
+ }
+ }
+
+ /**
+ * Perform request
+ *
+ * @throws IOException
+ */
+ public String getUrlResponse(String requestUrl)
+ {
+ String response = "";
+ HttpClient client = new HttpClient();
+ HttpMethod method = new GetMethod(requestUrl);
+ method.setRequestHeader("Accept", "*/*");
+ client.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler());
+ try
+ {
+ int statusCode = client.executeMethod(method);
+ if (statusCode == HttpStatus.SC_OK)
+ {
+ response = method.getResponseBodyAsString();
+ }
+ else
+ {
+ response = method.getStatusText();
+ }
+ }
+ catch (HttpException e)
+ {
+ response = e.getMessage();
+ }
+ catch (IOException e)
+ {
+ response = e.getMessage();
+ }
+ finally
+ {
+ // Release the connection.
+ method.releaseConnection();
+ }
+
+ return response;
+ }
+}
diff --git a/source/java/org/alfresco/web/bean/users/CreateUserWizard.java b/source/java/org/alfresco/web/bean/users/CreateUserWizard.java
index 915e7e2ed7..cfcc36aee8 100644
--- a/source/java/org/alfresco/web/bean/users/CreateUserWizard.java
+++ b/source/java/org/alfresco/web/bean/users/CreateUserWizard.java
@@ -75,6 +75,8 @@ public class CreateUserWizard extends BaseWizardBean
protected String companyId = null;
protected String homeSpaceName = "";
protected NodeRef homeSpaceLocation = null;
+ protected String presenceProvider = null;
+ protected String presenceUsername = null;
/** AuthenticationService bean reference */
private AuthenticationService authenticationService;
@@ -144,6 +146,8 @@ public class CreateUserWizard extends BaseWizardBean
this.companyId = "";
this.homeSpaceName = "";
this.homeSpaceLocation = getDefaultHomeSpace();
+ this.presenceProvider = "";
+ this.presenceUsername = "";
}
/**
@@ -187,6 +191,40 @@ public class CreateUserWizard extends BaseWizardBean
this.companyId = companyId;
}
+ /**
+ * @return Returns the presenceProvider.
+ */
+ public String getPresenceProvider()
+ {
+ return this.presenceProvider;
+ }
+
+ /**
+ * @param presenceProvider
+ * The presenceProvider to set.
+ */
+ public void setPresenceProvider(String presenceProvider)
+ {
+ this.presenceProvider = presenceProvider;
+ }
+
+ /**
+ * @return Returns the presenceUsername.
+ */
+ public String getPresenceUsername()
+ {
+ return this.presenceUsername;
+ }
+
+ /**
+ * @param presenceUsername
+ * The presenceUsername to set.
+ */
+ public void setPresenceUsername(String presenceUsername)
+ {
+ this.presenceUsername = presenceUsername;
+ }
+
/**
* @return Returns the email.
*/
diff --git a/source/java/org/alfresco/web/bean/users/EditUserWizard.java b/source/java/org/alfresco/web/bean/users/EditUserWizard.java
index dc9892b77a..525f319245 100644
--- a/source/java/org/alfresco/web/bean/users/EditUserWizard.java
+++ b/source/java/org/alfresco/web/bean/users/EditUserWizard.java
@@ -70,6 +70,8 @@ public class EditUserWizard extends CreateUserWizard
this.userName = (String) props.get("userName");
this.email = (String) props.get("email");
this.companyId = (String) props.get("organizationId");
+ this.presenceProvider = (String) props.get("presenceProvider");
+ this.presenceUsername = (String) props.get("presenceUsername");
// calculate home space name and parent space Id from homeFolderId
this.homeSpaceLocation = null; // default to Company root space
@@ -177,6 +179,8 @@ public class EditUserWizard extends CreateUserWizard
props.put(ContentModel.PROP_HOMEFOLDER, newHomeFolderRef);
props.put(ContentModel.PROP_EMAIL, this.email);
props.put(ContentModel.PROP_ORGID, this.companyId);
+ props.put(ContentModel.PROP_PRESENCEPROVIDER, this.presenceProvider);
+ props.put(ContentModel.PROP_PRESENCEUSERNAME, this.presenceUsername);
this.nodeService.setProperties(nodeRef, props);
// TODO: RESET HomeSpace Ref found in top-level navigation bar!
diff --git a/source/web/WEB-INF/faces-config-beans.xml b/source/web/WEB-INF/faces-config-beans.xml
index efdb6126e6..aa35d045a2 100644
--- a/source/web/WEB-INF/faces-config-beans.xml
+++ b/source/web/WEB-INF/faces-config-beans.xml
@@ -4044,6 +4044,15 @@
request
+
+
+ Bean proxying ajax calls for the online Presence webscript
+
+ PresenceProxyBean
+ org.alfresco.web.bean.ajax.PresenceProxyBean
+ request
+
+
Bean that returns manages the tree data for the navigator component
diff --git a/source/web/images/icons/presence_offline.gif b/source/web/images/icons/presence_offline.gif
new file mode 100644
index 0000000000..7c6d45be67
Binary files /dev/null and b/source/web/images/icons/presence_offline.gif differ
diff --git a/source/web/images/icons/presence_online.gif b/source/web/images/icons/presence_online.gif
new file mode 100644
index 0000000000..6c621aaf32
Binary files /dev/null and b/source/web/images/icons/presence_online.gif differ
diff --git a/source/web/images/icons/presence_unknown.gif b/source/web/images/icons/presence_unknown.gif
new file mode 100644
index 0000000000..d244428495
Binary files /dev/null and b/source/web/images/icons/presence_unknown.gif differ
diff --git a/source/web/jsp/users/person-properties.jsp b/source/web/jsp/users/person-properties.jsp
index ecd5c31868..2ac16d260a 100644
--- a/source/web/jsp/users/person-properties.jsp
+++ b/source/web/jsp/users/person-properties.jsp
@@ -86,4 +86,22 @@
+
+
+ : |
+
+
+
+
+
+
+ |
+
+
+ : |
+
+
+ |
+
+
\ No newline at end of file
diff --git a/source/web/scripts/ajax/presence.js b/source/web/scripts/ajax/presence.js
new file mode 100644
index 0000000000..7ae2e29346
--- /dev/null
+++ b/source/web/scripts/ajax/presence.js
@@ -0,0 +1,93 @@
+/*
+* Prerequisites: mootools.v1.11.js
+*/
+var Presence =
+{
+ init: function()
+ {
+ window.contextPath = Presence.getContextPath();
+
+ var users = $$("#presenceContainer .presenceStatus");
+ users.each(function(user, i)
+ {
+ // ajax call to load online status
+ var userDetails = user.attributes["rel"].value.split("|");
+ var proxyURL = window.contextPath + "/ajax/invoke/PresenceProxyBean.proxyRequest";
+ var statusURL = Presence.getStatusURL(userDetails);
+
+ if (statusURL != "")
+ {
+ var myAjax = new Ajax(proxyURL, {
+ method: 'get',
+ headers: {'If-Modified-Since': 'Sat, 1 Jan 2000 00:00:00 GMT'},
+ onComplete: function(textResponse, xmlResponse)
+ {
+ var statusType = Presence.getStatusType(userDetails[0], textResponse);
+ user.addClass(statusType);
+ }
+ });
+ myAjax.request("url=" + escape(statusURL));
+ }
+ else
+ {
+ user.addClass("unknown");
+ }
+ });
+ },
+
+ /* Calculates and returns the context path for the current page */
+ getContextPath: function()
+ {
+ var path = window.location.pathname;
+ var idx = path.indexOf("/", 1);
+ var contextPath = "";
+ if (idx != -1)
+ {
+ contextPath = path.substring(0, idx);
+ }
+ else
+ {
+ contextPath = "";
+ }
+
+ return contextPath;
+ },
+
+ getStatusURL: function(userDetails)
+ {
+ var provider = userDetails[0];
+ var username = userDetails[1];
+ var statusURL = "";
+
+ switch(provider)
+ {
+ case "skype":
+ statusURL = "http://mystatus.skype.com/" + username + ".txt";
+ break;
+ case "yahoo":
+ statusURL = "http://opi.yahoo.com/online?u=" + username + "&m=t&t=1";
+ break;
+ }
+
+ return statusURL;
+ },
+
+ getStatusType: function(provider, response)
+ {
+ var statusType = "unknown";
+
+ switch(provider)
+ {
+ case "skype":
+ statusType = (response == "Online") ? "online" : "offline";
+ break;
+ case "yahoo":
+ statusType = (response == "01") ? "online" : "offline";
+ break;
+ }
+
+ return statusType;
+ }
+}
+
+window.addEvent('domready', Presence.init);